feat: add token validation functionality for Hetzner and DigitalOcean providers
This commit is contained in:
parent
c95e297f39
commit
2a8fbb3f6e
3 changed files with 82 additions and 18 deletions
|
|
@ -30,6 +30,60 @@ public function loadTokens()
|
|||
$this->tokens = CloudProviderToken::ownedByCurrentTeam()->get();
|
||||
}
|
||||
|
||||
public function validateToken(int $tokenId)
|
||||
{
|
||||
try {
|
||||
$token = CloudProviderToken::ownedByCurrentTeam()->findOrFail($tokenId);
|
||||
$this->authorize('view', $token);
|
||||
|
||||
if ($token->provider === 'hetzner') {
|
||||
$isValid = $this->validateHetznerToken($token->token);
|
||||
if ($isValid) {
|
||||
$this->dispatch('success', 'Hetzner token is valid.');
|
||||
} else {
|
||||
$this->dispatch('error', 'Hetzner token validation failed. Please check the token.');
|
||||
}
|
||||
} elseif ($token->provider === 'digitalocean') {
|
||||
$isValid = $this->validateDigitalOceanToken($token->token);
|
||||
if ($isValid) {
|
||||
$this->dispatch('success', 'DigitalOcean token is valid.');
|
||||
} else {
|
||||
$this->dispatch('error', 'DigitalOcean token validation failed. Please check the token.');
|
||||
}
|
||||
} else {
|
||||
$this->dispatch('error', 'Unknown provider.');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
private function validateHetznerToken(string $token): bool
|
||||
{
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::withToken($token)
|
||||
->timeout(10)
|
||||
->get('https://api.hetzner.cloud/v1/servers?per_page=1');
|
||||
|
||||
return $response->successful();
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function validateDigitalOceanToken(string $token): bool
|
||||
{
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::withToken($token)
|
||||
->timeout(10)
|
||||
->get('https://api.digitalocean.com/v2/account');
|
||||
|
||||
return $response->successful();
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteToken(int $tokenId)
|
||||
{
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -14,13 +14,14 @@
|
|||
<x-forms.input required id="name" label="Token Name"
|
||||
placeholder="e.g., Production Hetzner. tip: add Hetzner project name to identify easier" />
|
||||
|
||||
<x-forms.input required type="password" id="token" label="API Token" placeholder="Enter your API token" />
|
||||
<x-forms.input required type="password" id="token" label="API Token"
|
||||
placeholder="Enter your API token" />
|
||||
|
||||
@if (auth()->user()->currentTeam()->cloudProviderTokens->where('provider', $provider)->isEmpty())
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
Create an API token in the <a
|
||||
href='{{ $provider === 'hetzner' ? 'https://console.hetzner.com/projects' : '#' }}' target='_blank'
|
||||
class='underline dark:text-white'>{{ ucfirst($provider) }} Console</a> → choose
|
||||
href='{{ $provider === 'hetzner' ? 'https://console.hetzner.com/projects' : '#' }}'
|
||||
target='_blank' class='underline dark:text-white'>{{ ucfirst($provider) }} Console</a> → choose
|
||||
Project → Security → API Tokens.
|
||||
@if ($provider === 'hetzner')
|
||||
<br><br>
|
||||
|
|
@ -28,12 +29,12 @@ class='underline dark:text-white'>{{ ucfirst($provider) }} Console</a> → choos
|
|||
class='underline dark:text-white'>Sign up here</a>
|
||||
<br>
|
||||
<span class="text-xs">(Coolify's affiliate link, only new accounts - supports us (€10)
|
||||
and gives you €20)</span>
|
||||
and gives you €20)</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<x-forms.button type="submit" wire:target="addToken">Validate & Add Token</x-forms.button>
|
||||
<x-forms.button type="submit">Validate & Add Token</x-forms.button>
|
||||
@else
|
||||
{{-- Full page layout: horizontal, spacious --}}
|
||||
<div class="flex gap-2 items-end flex-wrap">
|
||||
|
|
@ -49,7 +50,8 @@ class='underline dark:text-white'>Sign up here</a>
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex-1 min-w-64">
|
||||
<x-forms.input required type="password" id="token" label="API Token" placeholder="Enter your API token" />
|
||||
<x-forms.input required type="password" id="token" label="API Token"
|
||||
placeholder="Enter your API token" />
|
||||
@if (auth()->user()->currentTeam()->cloudProviderTokens->where('provider', $provider)->isEmpty())
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400 mt-2">
|
||||
Create an API token in the <a href='https://console.hetzner.com/projects' target='_blank'
|
||||
|
|
@ -60,11 +62,11 @@ class='underline dark:text-white'>Hetzner Console</a> → choose Project → Sec
|
|||
class='underline dark:text-white'>Sign up here</a>
|
||||
<br>
|
||||
<span class="text-xs">(Coolify's affiliate link, only new accounts - supports us (€10)
|
||||
and gives you €20)</span>
|
||||
and gives you €20)</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<x-forms.button type="submit" wire:target="addToken">Validate & Add Token</x-forms.button>
|
||||
<x-forms.button type="submit">Validate & Add Token</x-forms.button>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,16 +20,24 @@ class="flex flex-col gap-1 p-2 border dark:border-coolgray-200 hover:no-underlin
|
|||
</div>
|
||||
<div class="text-sm">Created: {{ $savedToken->created_at->diffForHumans() }}</div>
|
||||
|
||||
@can('delete', $savedToken)
|
||||
<x-modal-confirmation title="Confirm Token Deletion?" isErrorButton buttonTitle="Delete Token"
|
||||
submitAction="deleteToken({{ $savedToken->id }})" :actions="[
|
||||
'This cloud provider token will be permanently deleted.',
|
||||
'Any servers using this token will need to be reconfigured.',
|
||||
]"
|
||||
confirmationText="{{ $savedToken->name }}"
|
||||
confirmationLabel="Please confirm the deletion by entering the token name below"
|
||||
shortConfirmationLabel="Token Name" :confirmWithPassword="false" step2ButtonText="Delete Token" />
|
||||
@endcan
|
||||
<div class="flex gap-2 pt-2">
|
||||
@can('view', $savedToken)
|
||||
<x-forms.button wire:click="validateToken({{ $savedToken->id }})" type="button">
|
||||
Validate Token
|
||||
</x-forms.button>
|
||||
@endcan
|
||||
|
||||
@can('delete', $savedToken)
|
||||
<x-modal-confirmation title="Confirm Token Deletion?" isErrorButton buttonTitle="Delete Token"
|
||||
submitAction="deleteToken({{ $savedToken->id }})" :actions="[
|
||||
'This cloud provider token will be permanently deleted.',
|
||||
'Any servers using this token will need to be reconfigured.',
|
||||
]"
|
||||
confirmationText="{{ $savedToken->name }}"
|
||||
confirmationLabel="Please confirm the deletion by entering the token name below"
|
||||
shortConfirmationLabel="Token Name" :confirmWithPassword="false" step2ButtonText="Delete Token" />
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue