diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index f5ea2ae80..a85306f6b 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -3,6 +3,7 @@ namespace App\Livewire\Server\New; use App\Enums\ProxyTypes; +use App\Models\PrivateKey; use App\Models\Server; use App\Models\Team; use App\Rules\ValidServerIp; @@ -84,11 +85,51 @@ protected function messages(): array ]); } + public function getListeners(): array + { + return [ + 'privateKeyCreated' => 'handlePrivateKeyCreated', + ]; + } + public function setPrivateKey(string $private_key_id) { $this->private_key_id = $private_key_id; } + public function generatePrivateKey(string $type): void + { + try { + $this->authorize('create', PrivateKey::class); + + if (! in_array($type, ['ed25519', 'rsa'], true)) { + $this->dispatch('error', 'Invalid private key type.'); + + return; + } + + $keyData = PrivateKey::generateNewKeyPair($type); + $privateKey = PrivateKey::createAndStore([ + 'name' => $keyData['name'], + 'description' => $keyData['description'], + 'private_key' => $keyData['private_key'], + 'team_id' => currentTeam()->id, + ]); + + $this->handlePrivateKeyCreated($privateKey->id); + $this->dispatch('success', 'Private key created successfully.'); + } catch (\Throwable $e) { + handleError($e, $this); + } + } + + public function handlePrivateKeyCreated($keyId): void + { + $this->private_keys = PrivateKey::ownedAndOnlySShKeys()->where('id', '!=', 0)->get(); + $this->private_key_id = $keyId; + $this->resetErrorBag('private_key_id'); + } + public function instantSave() { // $this->dispatch('success', 'Application settings updated!'); diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index e41342ca2..39d9ca0fe 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -16,16 +16,65 @@
Non-root user is experimental: docs.
- - - @foreach ($private_keys as $key) - @if ($loop->first) - - @else - - @endif - @endforeach - +
+
+ + + @foreach ($private_keys as $key) + + @endforeach + +
+ @can('create', App\Models\PrivateKey::class) +
+ + + Add + + + + + +
+
+
+ + + + + Generate ED25519 + + + + + + Generate RSA + + + + + + + +
+
+
+
+ @endcan +
'file']); + Storage::fake('ssh-keys'); + + InstanceSettings::forceCreate(['id' => 0, 'is_api_enabled' => true]); + + $this->team = Team::factory()->create(); + $this->user = User::factory()->create(); + $this->team->members()->attach($this->user->id, ['role' => 'owner']); + + session(['currentTeam' => $this->team]); + + $this->actingAs($this->user); + + $this->existingPrivateKey = PrivateKey::withoutEvents(fn () => PrivateKey::forceCreate([ + 'uuid' => (string) new Cuid2, + 'name' => 'Existing SSH Key', + 'description' => 'Existing SSH Key', + 'private_key' => 'test-private-key', + 'team_id' => $this->team->id, + ])); +}); + +it('generates and preselects a new private key without clearing server form data', function () { + $component = Livewire::test(ByIp::class, [ + 'private_keys' => collect([$this->existingPrivateKey]), + 'limit_reached' => false, + ]) + ->set('name', 'Production Server') + ->set('description', 'Deploy target') + ->set('ip', '192.0.2.50') + ->set('user', 'deploy.user') + ->set('port', 2222) + ->set('is_build_server', true) + ->call('generatePrivateKey', 'ed25519') + ->assertHasNoErrors() + ->assertSet('name', 'Production Server') + ->assertSet('description', 'Deploy target') + ->assertSet('ip', '192.0.2.50') + ->assertSet('user', 'deploy.user') + ->assertSet('port', 2222) + ->assertSet('is_build_server', true); + + $newPrivateKeyId = $component->get('private_key_id'); + + expect($newPrivateKeyId)->not->toBe($this->existingPrivateKey->id) + ->and(PrivateKey::find($newPrivateKeyId))->not->toBeNull() + ->and($component->get('private_keys')->pluck('id'))->toContain($newPrivateKeyId); +}); + +it('preselects a manually added private key without clearing server form data', function () { + $manualPrivateKey = PrivateKey::withoutEvents(fn () => PrivateKey::forceCreate([ + 'uuid' => (string) new Cuid2, + 'name' => 'Manual SSH Key', + 'description' => 'Manual SSH Key', + 'private_key' => 'manual-test-private-key', + 'team_id' => $this->team->id, + ])); + + Livewire::test(ByIp::class, [ + 'private_keys' => collect([$this->existingPrivateKey]), + 'limit_reached' => false, + ]) + ->set('name', 'Production Server') + ->set('description', 'Deploy target') + ->set('ip', '192.0.2.51') + ->set('user', 'deploy.user') + ->set('port', 2222) + ->set('is_build_server', true) + ->call('handlePrivateKeyCreated', $manualPrivateKey->id) + ->assertSet('private_key_id', $manualPrivateKey->id) + ->assertSet('name', 'Production Server') + ->assertSet('description', 'Deploy target') + ->assertSet('ip', '192.0.2.51') + ->assertSet('user', 'deploy.user') + ->assertSet('port', 2222) + ->assertSet('is_build_server', true) + ->assertSee('Manual SSH Key'); +});