clusev/tests/Feature/FirstFactorCodesTest.php

74 lines
2.3 KiB
PHP

<?php
namespace Tests\Feature;
use App\Livewire\Auth\TwoFactorSetup;
use App\Livewire\Settings\WebauthnKeys;
use App\Models\User;
use App\Models\WebauthnCredential;
use App\Services\WebauthnService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Mockery;
use PragmaRX\Google2FAQRCode\Google2FA;
use Tests\TestCase;
class FirstFactorCodesTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function test_first_totp_confirm_generates_codes_and_opens_modal(): void
{
$user = User::factory()->create();
$g = new Google2FA;
$secret = $g->generateSecretKey();
Livewire::actingAs($user)->test(TwoFactorSetup::class)
->set('secret', $secret)
->set('code', $g->getCurrentOtp($secret))
->call('confirm')
->assertRedirect(route('settings'));
$this->assertTrue($user->fresh()->hasRecoveryCodes());
$this->assertTrue(session('open_recovery_modal'));
}
public function test_first_key_register_generates_codes_and_opens_modal(): void
{
$user = User::factory()->create();
$svc = Mockery::mock(WebauthnService::class);
$svc->shouldReceive('available')->andReturnTrue();
$svc->shouldReceive('verifyRegistration')->andReturnUsing(fn ($u, $a, $name) => WebauthnCredential::create([
'user_id' => $u->id, 'name' => $name, 'credential_id' => 'cid', 'public_key' => '{}', 'sign_count' => 0,
]));
app()->instance(WebauthnService::class, $svc);
Livewire::actingAs($user)->test(WebauthnKeys::class)
->set('newName', 'YubiKey 5C')
->call('register', ['dummy' => true], $svc)
->assertDispatched('openModal');
$this->assertTrue($user->fresh()->hasRecoveryCodes());
}
public function test_malformed_setup_secret_yields_validation_error_not_500(): void
{
$user = User::factory()->create();
Livewire::actingAs($user)->test(TwoFactorSetup::class)
->set('secret', 'x') // client-tampered, too short for Google2FA
->set('code', '123456')
->call('confirm')
->assertHasErrors('code');
$this->assertFalse($user->fresh()->hasTotp());
}
}