fix(admin): the admin password is shown once, and means it
tests / pest (push) Successful in 7m37s Details
tests / assets (push) Successful in 22s Details
tests / release (push) Has been skipped Details

The handoff stayed in the cache for its full ten minutes, so any replayed
component request could fetch the plaintext again — "shown once" was a figure
of speech. It is consumed on the first read and the token dropped; the payload
reaches the view and nothing else.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/portal-design
nexxo 2026-07-26 05:34:57 +02:00
parent d40113be8e
commit 55b1a1468f
2 changed files with 35 additions and 1 deletions

View File

@ -82,9 +82,21 @@ class InstanceAdminAccess extends ModalComponent
public function render() public function render()
{ {
$payload = null; $payload = null;
if ($this->token !== null) { if ($this->token !== null) {
$raw = ConfigHandoff::get($this->token); $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', [ return view('livewire.admin.instance-admin-access', [

View File

@ -114,3 +114,25 @@ it('tells the console when Proxmox is unreachable', function () {
// Otherwise the modal polls forever with a spinner. // Otherwise the modal polls forever with a spinner.
expect(json_decode(ConfigHandoff::get('handoff-throw'), true))->toBe(['error' => 'failed']); 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'));
});