new funcionality
This commit is contained in:
129
tests/Feature/Auth/TwoFactorTest.php
Normal file
129
tests/Feature/Auth/TwoFactorTest.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TwoFactorTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_setup_generates_a_pending_secret_and_qr_url(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create();
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/web-api/2fa/setup');
|
||||
|
||||
$response->assertOk()->assertJsonStructure(['secret', 'otpauth_url']);
|
||||
|
||||
$user->refresh();
|
||||
$this->assertNotNull($user->two_factor_secret);
|
||||
$this->assertFalse($user->hasTwoFactorEnabled());
|
||||
}
|
||||
|
||||
public function test_setup_is_blocked_when_already_enabled(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create([
|
||||
'two_factor_secret' => (new Google2FA())->generateSecretKey(),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/setup')->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_confirm_enables_two_factor_and_returns_recovery_codes(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create();
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/setup')->assertOk();
|
||||
$user->refresh();
|
||||
|
||||
$code = (new Google2FA())->getCurrentOtp($user->two_factor_secret);
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/web-api/2fa/confirm', ['code' => $code]);
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertCount(8, $response->json('recovery_codes'));
|
||||
|
||||
$user->refresh();
|
||||
$this->assertTrue($user->hasTwoFactorEnabled());
|
||||
$this->assertDatabaseHas('audit_logs', [
|
||||
'action' => 'user.2fa_enabled',
|
||||
'subject_id' => (string) $user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_confirm_rejects_invalid_code(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create();
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/setup')->assertOk();
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/web-api/2fa/confirm', ['code' => '000000']);
|
||||
|
||||
$response->assertUnprocessable()->assertJsonValidationErrors('code');
|
||||
$this->assertFalse($user->fresh()->hasTwoFactorEnabled());
|
||||
}
|
||||
|
||||
public function test_confirm_without_pending_setup_fails(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create();
|
||||
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/confirm', ['code' => '123456'])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_disable_requires_correct_password(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create([
|
||||
'password' => Hash::make('password123'),
|
||||
'two_factor_secret' => (new Google2FA())->generateSecretKey(),
|
||||
'two_factor_recovery_codes' => ['AAAA-1111'],
|
||||
'two_factor_confirmed_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/disable', ['password' => 'nope'])
|
||||
->assertUnprocessable()->assertJsonValidationErrors('password');
|
||||
$this->assertTrue($user->fresh()->hasTwoFactorEnabled());
|
||||
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/disable', ['password' => 'password123'])
|
||||
->assertNoContent();
|
||||
|
||||
$user->refresh();
|
||||
$this->assertFalse($user->hasTwoFactorEnabled());
|
||||
$this->assertNull($user->two_factor_secret);
|
||||
$this->assertNull($user->two_factor_recovery_codes);
|
||||
$this->assertDatabaseHas('audit_logs', ['action' => 'user.2fa_disabled']);
|
||||
}
|
||||
|
||||
public function test_regenerate_recovery_codes_requires_enabled_two_factor(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create(['password' => Hash::make('password123')]);
|
||||
|
||||
$this->actingAs($user)->postJson('/web-api/2fa/recovery-codes', ['password' => 'password123'])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
public function test_regenerate_recovery_codes_replaces_old_codes(): void
|
||||
{
|
||||
$user = User::factory()->approved()->create([
|
||||
'password' => Hash::make('password123'),
|
||||
'two_factor_secret' => (new Google2FA())->generateSecretKey(),
|
||||
'two_factor_recovery_codes' => ['OLD1-CODE', 'OLD2-CODE'],
|
||||
'two_factor_confirmed_at' => now(),
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/web-api/2fa/recovery-codes', ['password' => 'password123']);
|
||||
|
||||
$response->assertOk();
|
||||
$newCodes = $response->json('recovery_codes');
|
||||
$this->assertCount(8, $newCodes);
|
||||
$this->assertNotContains('OLD1-CODE', $newCodes);
|
||||
|
||||
$user->refresh();
|
||||
$this->assertEquals($newCodes, $user->two_factor_recovery_codes);
|
||||
$this->assertDatabaseHas('audit_logs', ['action' => 'user.2fa_recovery_regenerated']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user