fix(auth): R15 review — restore one-time-code autofill, memoise pendingUser in verify
- backup field: autocomplete=off -> one-time-code (backup codes ARE one-time codes; matches the main challenge field, the rest of the app, and the spec; restores password-manager OTP autofill that the earlier polish broke) - both verify() use the trait's memoised $this->pendingUser() instead of a fresh User::find(), saving a redundant query on the failed-attempt re-render (Pint dropped the now-unused User import in TwoFactorBackup) - spec: align trait backing-state visibility note to the implemented 'private' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/v1-foundation
parent
7c1a32518d
commit
4ea4050c80
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Livewire\Auth;
|
||||
|
||||
use App\Livewire\Concerns\CompletesTwoFactorChallenge;
|
||||
use App\Models\User;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Validate;
|
||||
|
|
@ -30,7 +29,7 @@ class TwoFactorBackup extends Component
|
|||
|
||||
$this->assertNotRateLimited();
|
||||
|
||||
$user = User::find(session('2fa.user'));
|
||||
$user = $this->pendingUser();
|
||||
|
||||
if (! $user || ! $user->hasTwoFactorEnabled()) {
|
||||
session()->forget(['2fa.user', '2fa.remember']);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class TwoFactorChallenge extends Component
|
|||
|
||||
$this->assertNotRateLimited();
|
||||
|
||||
$user = User::find(session('2fa.user'));
|
||||
$user = $this->pendingUser();
|
||||
|
||||
if (! $user || ! $user->hasTwoFactorEnabled()) {
|
||||
session()->forget(['2fa.user', '2fa.remember']);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ Extract the logic currently inline in `TwoFactorChallenge` into a trait used by
|
|||
components, so there is no duplication and **one shared rate-limit bucket set**:
|
||||
|
||||
- `pendingUser(): ?User` — the memoised `User::find(session('2fa.user'))` resolver (move the existing
|
||||
one; keep its backing state `protected` so both components share it).
|
||||
one; keep its backing state `private` — an internal memoisation detail; each component gets its
|
||||
own copy, and Livewire persists only public props, so the visibility is runtime-irrelevant).
|
||||
- `getPendingHasTotpProperty(): bool` — **keep the existing Livewire computed-property magic getter**
|
||||
(move it verbatim into the trait, do **not** turn it into a plain `pendingHasTotp()` method). This
|
||||
keeps every blade's `$this->pendingHasTotp` usage working unchanged — **no property→method rewrites
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<form wire:submit="verify" class="space-y-4">
|
||||
<div>
|
||||
<label for="code" class="{{ $label }}">{{ __('auth.challenge_backup_label') }}</label>
|
||||
<input wire:model="code" id="code" inputmode="text" autocomplete="off" autofocus
|
||||
<input wire:model="code" id="code" inputmode="text" autocomplete="one-time-code" autofocus
|
||||
class="{{ $fieldText }}" placeholder="{{ __('auth.challenge_backup_placeholder') }}" />
|
||||
@error('code') <p class="{{ $err }}"><x-icon name="alert" class="h-3.5 w-3.5 shrink-0" />{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue