diff --git a/app/Livewire/Auth/TwoFactorChallenge.php b/app/Livewire/Auth/TwoFactorChallenge.php index 3e946e0..e30e777 100644 --- a/app/Livewire/Auth/TwoFactorChallenge.php +++ b/app/Livewire/Auth/TwoFactorChallenge.php @@ -18,6 +18,21 @@ class TwoFactorChallenge extends Component #[Validate('required|string')] public string $code = ''; + private ?User $pendingUser = null; + + private bool $pendingResolved = false; + + /** The pending 2FA user, resolved once per request from the session. */ + private function pendingUser(): ?User + { + if (! $this->pendingResolved) { + $this->pendingUser = User::find(session('2fa.user')); + $this->pendingResolved = true; + } + + return $this->pendingUser; + } + public function mount() { if (! session()->has('2fa.user')) { @@ -28,7 +43,7 @@ class TwoFactorChallenge extends Component /** Whether the PENDING user has TOTP — the authenticator code field renders only then. */ public function getPendingHasTotpProperty(): bool { - return (bool) User::find(session('2fa.user'))?->hasTotp(); + return (bool) $this->pendingUser()?->hasTotp(); } public function verify() @@ -74,7 +89,7 @@ class TwoFactorChallenge extends Component /** Whether to offer the security-key option for the pending user (domain+HTTPS + has a key). */ public function webauthnAvailable(): bool { - $user = User::find(session('2fa.user')); + $user = $this->pendingUser(); return $user !== null && app(WebauthnService::class)->available() diff --git a/lang/de/auth.php b/lang/de/auth.php index 7b9a66b..2f97319 100644 --- a/lang/de/auth.php +++ b/lang/de/auth.php @@ -77,7 +77,7 @@ return [ 'challenge_key_subtitle' => 'Bestätige mit deinem Security-Key oder einem Backup-Code.', 'challenge_backup_label' => 'Backup-Code', 'challenge_backup_placeholder' => 'xxxxxxxxxx-xxxxxxxxxx', - 'challenge_backup_only_hint' => 'Kein Authenticator nötig — Security-Key oben oder ein Backup-Code.', + 'challenge_backup_only_hint' => 'Kein Authenticator nötig — Security-Key oder ein Backup-Code.', 'recovery_heading' => 'Backup-Codes', 'recovery_subtitle' => 'Mit diesen Einmal-Codes meldest du dich an, wenn du keinen Authenticator hast.', 'recovery_warning' => 'Speichere diese Codes jetzt sicher ab — jeder Code funktioniert genau einmal. Lade sie herunter, solange sie angezeigt werden.', diff --git a/lang/en/auth.php b/lang/en/auth.php index 9d040a8..9248f68 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -77,7 +77,7 @@ return [ 'challenge_key_subtitle' => 'Confirm with your security key or a backup code.', 'challenge_backup_label' => 'Backup code', 'challenge_backup_placeholder' => 'xxxxxxxxxx-xxxxxxxxxx', - 'challenge_backup_only_hint' => 'No authenticator needed — use the security key above or a backup code.', + 'challenge_backup_only_hint' => 'No authenticator needed — use a security key or a backup code.', 'recovery_heading' => 'Backup codes', 'recovery_subtitle' => 'Use these one-time codes to sign in when you do not have your authenticator.', 'recovery_warning' => 'Save these codes somewhere safe now — each works exactly once. Download them while they are shown.', diff --git a/tests/Feature/ChallengeFactorAdaptTest.php b/tests/Feature/ChallengeFactorAdaptTest.php index 3678990..8e75dd6 100644 --- a/tests/Feature/ChallengeFactorAdaptTest.php +++ b/tests/Feature/ChallengeFactorAdaptTest.php @@ -29,6 +29,8 @@ class ChallengeFactorAdaptTest extends TestCase Livewire::test(TwoFactorChallenge::class) ->assertSet('pendingHasTotp', false) + ->assertDontSee('000000') + ->assertSee(__('auth.challenge_backup_label')) ->set('code', $codes[0]) ->call('verify') ->assertRedirect(route('dashboard'));