diff --git a/app/Livewire/Auth/TwoFactorChallenge.php b/app/Livewire/Auth/TwoFactorChallenge.php index 1557b97..29aacc0 100644 --- a/app/Livewire/Auth/TwoFactorChallenge.php +++ b/app/Livewire/Auth/TwoFactorChallenge.php @@ -24,8 +24,8 @@ class TwoFactorChallenge extends Component return $this->redirect(route('login'), navigate: true); } - // No TOTP and no usable security key (a key-only user over http + bare IP, where WebAuthn - // has no secure context) → the backup code is the only path: go straight to its own view. + // No TOTP and webauthnAvailable() is false (no registered key, or — for a key-only user — + // no secure context on http + bare IP) → the backup code is the only path: go to its view. if (! $this->pendingHasTotp && ! $this->webauthnAvailable()) { return $this->redirect(route('two-factor.challenge.backup'), navigate: true); } diff --git a/tests/Feature/ChallengeFactorAdaptTest.php b/tests/Feature/ChallengeFactorAdaptTest.php index f96d3b3..c0af663 100644 --- a/tests/Feature/ChallengeFactorAdaptTest.php +++ b/tests/Feature/ChallengeFactorAdaptTest.php @@ -67,4 +67,20 @@ class ChallengeFactorAdaptTest extends TestCase ->assertDontSee('000000') // no TOTP field ->assertDontSee(__('auth.challenge_backup_placeholder')); // no inline backup field } + + public function test_totp_and_key_user_with_secure_context_sees_field_key_alt_and_backup(): void + { + $svc = $this->mock(WebauthnService::class); + $svc->shouldReceive('available')->andReturn(true); + + $user = User::factory()->create(['two_factor_secret' => 'S', 'two_factor_confirmed_at' => now()]); + WebauthnCredential::create(['user_id' => $user->id, 'name' => 'k', 'credential_id' => 'cid', 'public_key' => '{}', 'sign_count' => 0]); + session(['2fa.user' => $user->id, '2fa.remember' => false]); + + Livewire::test(TwoFactorChallenge::class) + ->assertNoRedirect() + ->assertSee('000000') // TOTP field + ->assertSee(__('auth.webauthn_login')) // secondary security-key button (nested branch) + ->assertSee(__('auth.challenge_use_backup')); // backup link + } }