*/ public array $zones = []; public bool $automaticDns = true; public function mount(string $integration_token_uuid): void { $this->integrationToken = IntegrationToken::ownedByCurrentTeam() ->whereUuid($integration_token_uuid) ->firstOrFail(); $this->authorize('view', $this->integrationToken); $this->name = $this->integrationToken->name; $this->capabilities = $this->integrationToken->capabilities; $this->metadata = $this->integrationToken->metadata ?? []; $this->loadZones(); $this->automaticDns = $this->integrationToken->automaticDnsEnabled(); } protected function rules(): array { $allowedCapability = $this->integrationToken->provider === 'cloudflare' ? 'dns' : 'secrets'; $rules = [ 'name' => ['required', 'string', 'max:255'], 'newToken' => ['nullable', 'string'], 'capabilities' => ['required', 'array', 'min:1'], 'capabilities.*' => ['required', 'in:'.$allowedCapability], 'automaticDns' => ['boolean'], ]; if ($this->integrationToken->provider === 'infisical') { $rules['metadata.base_url'] = ['required', 'url']; $rules['metadata.client_id'] = ['required', 'string']; } if ($this->integrationToken->provider === 'vault') { $rules['metadata.base_url'] = ['required', 'url']; $rules['metadata.namespace'] = ['nullable', 'string']; } return $rules; } protected function messages(): array { return [ 'capabilities.required' => 'Select at least one capability.', 'capabilities.min' => 'Select at least one capability.', ]; } public function save(IntegrationTokenValidator $validator, CloudflareDnsProvider $cloudflare): void { $this->authorize('update', $this->integrationToken); $validated = $this->validate(); $provider = $this->integrationToken->provider; $token = filled($validated['newToken']) ? $validated['newToken'] : $this->integrationToken->token; $metadata = array_filter(data_get($validated, 'metadata', []), fn ($value) => filled($value)); if ($provider === 'cloudflare') { if ($validated['automaticDns']) { unset($metadata['automatic_dns']); } else { $metadata['automatic_dns'] = false; } } $capabilitiesChanged = collect($validated['capabilities'])->sort()->values()->all() !== collect($this->integrationToken->capabilities)->sort()->values()->all(); $metadataChanged = $metadata != ($this->integrationToken->metadata ?? []); try { if ((filled($validated['newToken']) || $capabilitiesChanged || $metadataChanged) && ! $validator->validate($provider, $token, $validated['capabilities'], $metadata)) { $this->dispatch('error', $validator->errorMessage($provider)); return; } $updates = [ 'name' => $validated['name'], 'capabilities' => $validated['capabilities'], 'metadata' => $metadata ?: null, ]; if (filled($validated['newToken'])) { $updates['token'] = $validated['newToken']; } DB::transaction(function () use ($updates, $provider, $validated, $capabilitiesChanged, $cloudflare): void { $this->integrationToken->update($updates); if ($provider === 'cloudflare' && (filled($validated['newToken']) || $capabilitiesChanged)) { $cloudflare->syncZones($this->integrationToken); } }); $this->newToken = ''; $this->loadZones(); auditLog('ui.integration_token.updated', [ 'team_id' => currentTeam()->id, 'integration_token_uuid' => $this->integrationToken->uuid, 'integration_token_name' => $this->integrationToken->name, 'provider' => $this->integrationToken->provider, 'rotated' => array_key_exists('token', $updates), ]); $this->dispatch( 'integration-token-updated', uuid: $this->integrationToken->uuid, name: $this->integrationToken->name, capabilities: $this->integrationToken->capabilities, ); $this->dispatch('success', 'Integration token updated successfully.'); } catch (\Throwable $e) { handleError($e, $this); } } public function delete(string $password = ''): void { $this->authorize('delete', $this->integrationToken); if ($this->integrationToken->secretManagerLinks()->exists()) { $this->dispatch('error', 'This token is used by one or more resources as a secret manager source. Remove those links first.'); return; } if ($this->integrationToken->managedDnsRecords()->exists()) { $this->dispatch('error', 'This token manages DNS records. Remove those domains or records first.'); return; } $uuid = $this->integrationToken->uuid; $name = $this->integrationToken->name; $provider = $this->integrationToken->provider; $this->integrationToken->delete(); auditLog('ui.integration_token.deleted', [ 'team_id' => currentTeam()->id, 'integration_token_uuid' => $uuid, 'integration_token_name' => $name, 'provider' => $provider, ]); $this->dispatch('integration-token-deleted', uuid: $this->integrationToken->uuid); $this->dispatch('close-modal'); $this->dispatch('success', 'Integration token deleted successfully.'); } public function refreshZones(CloudflareDnsProvider $cloudflare): void { $this->authorize('update', $this->integrationToken); try { $cloudflare->syncZones($this->integrationToken); $this->integrationToken->refresh(); $this->loadZones(); $this->dispatch('success', "Cloudflare zones refreshed. {$this->zoneCount} accessible zones found."); } catch (\Throwable $e) { handleError($e, $this); } } public function render() { return view('livewire.security.integration-token-editor'); } private function loadZones(): void { $this->zones = $this->integrationToken->dnsZones() ->select(['id', 'integration_token_id', 'name', 'account_name']) ->withCount('managedRecords') ->orderBy('name') ->get() ->map(fn ($zone) => [ 'id' => $zone->id, 'name' => $zone->name, 'account_name' => $zone->account_name, 'managed_records_count' => $zone->managed_records_count, ]) ->all(); $this->zoneCount = count($this->zones); } }