diff --git a/app/Livewire/Admin/InstanceAdminAccess.php b/app/Livewire/Admin/InstanceAdminAccess.php index 97053c1..ba52e75 100644 --- a/app/Livewire/Admin/InstanceAdminAccess.php +++ b/app/Livewire/Admin/InstanceAdminAccess.php @@ -82,9 +82,21 @@ class InstanceAdminAccess extends ModalComponent public function render() { $payload = null; + if ($this->token !== null) { $raw = ConfigHandoff::get($this->token); - $payload = $raw === null ? null : json_decode($raw, true); + + if ($raw !== null) { + // Consumed on the first read: leaving it in the cache would make + // "shown once" a figure of speech — any replayed component + // request could fetch the password again for ten minutes. The + // payload lives in a local variable, so it reaches the view and + // nothing else. + ConfigHandoff::forget($this->token); + $this->token = null; + $this->waiting = false; + $payload = json_decode($raw, true); + } } return view('livewire.admin.instance-admin-access', [ diff --git a/tests/Feature/Admin/InstanceAdminAccessTest.php b/tests/Feature/Admin/InstanceAdminAccessTest.php index 62a8f2c..1490711 100644 --- a/tests/Feature/Admin/InstanceAdminAccessTest.php +++ b/tests/Feature/Admin/InstanceAdminAccessTest.php @@ -114,3 +114,25 @@ it('tells the console when Proxmox is unreachable', function () { // Otherwise the modal polls forever with a spinner. expect(json_decode(ConfigHandoff::get('handoff-throw'), true))->toBe(['error' => 'failed']); }); + +it('shows the password once and not a second time', function () { + $pve = new FakeProxmoxClient; + app()->instance(ProxmoxClient::class, $pve); + $instance = adminAccessInstance(); + $owner = operator('Owner'); + $owner->forceFill(['password' => Hash::make('geheim-1234')])->save(); + + $modal = Livewire\Livewire::actingAs($owner) + ->test(InstanceAdminAccess::class, ['uuid' => $instance->uuid]) + ->set('password', 'geheim-1234') + ->call('request'); // sync queue: the job runs immediately + + $token = $modal->get('token'); + $modal->assertSee(__('instances.admin_ready')); + + // "Shown once" has to mean it: a replayed request must not fetch it again. + expect(ConfigHandoff::get($token ?? 'none'))->toBeNull() + ->and($modal->get('token'))->toBeNull(); + + $modal->call('$refresh')->assertDontSee(__('instances.admin_ready')); +});