feat: add routes, lang, tests, stubs, docs, and docker configurations
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UserTrustedDevice;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
test('guest without 2fa session is redirected to login', function () {
|
||||
$this->get('/2fa')->assertRedirect(route('login', absolute: false));
|
||||
});
|
||||
|
||||
test('2fa view renders when 2fa session is set', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '654321');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->get('/2fa')->assertOk()->assertViewIs('auth.two-factor');
|
||||
});
|
||||
|
||||
test('verify with correct code logs the user in', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '111222');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '111222'])
|
||||
->assertRedirect(route('dashboard', absolute: false));
|
||||
|
||||
$this->assertAuthenticatedAs($user);
|
||||
});
|
||||
|
||||
test('verify with wrong code keeps user logged out', function () {
|
||||
$user = User::factory()->create();
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '111222');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '999999'])
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('verify with expired code redirects to login', function () {
|
||||
$user = User::factory()->create();
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '111222');
|
||||
Session::put('auth.2fa_expires_at', now()->subSecond()->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '111222'])
|
||||
->assertRedirect(route('login', absolute: false))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('verify rejects code with wrong length', function () {
|
||||
$user = User::factory()->create();
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '111222');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '12345'])->assertSessionHasErrors('code');
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('trust device option persists a trusted device row', function () {
|
||||
$user = User::factory()->create();
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '888888');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '888888', 'trust_device' => '1']);
|
||||
|
||||
expect(UserTrustedDevice::where('user_id', $user->id)->count())->toBe(1);
|
||||
});
|
||||
|
||||
test('trust device defaults to no row when option is unset', function () {
|
||||
$user = User::factory()->create();
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '777777');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->post('/2fa', ['code' => '777777']);
|
||||
|
||||
expect(UserTrustedDevice::where('user_id', $user->id)->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('trusted device cookie skips 2fa view and auto-logs-in', function () {
|
||||
$user = User::factory()->create();
|
||||
$deviceId = (string) Str::uuid();
|
||||
$secret = Str::random(64);
|
||||
|
||||
UserTrustedDevice::create([
|
||||
'user_id' => $user->id,
|
||||
'device_id' => $deviceId,
|
||||
'token' => hash('sha256', $secret),
|
||||
'expires_at' => now()->addDays(30),
|
||||
]);
|
||||
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '000000');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->withCookie('2fa_trust_device', $deviceId.'|'.$secret)
|
||||
->get('/2fa')
|
||||
->assertRedirect(route('dashboard', absolute: false));
|
||||
|
||||
$this->assertAuthenticatedAs($user);
|
||||
});
|
||||
|
||||
test('trusted device cookie with wrong secret does not auto-login', function () {
|
||||
$user = User::factory()->create();
|
||||
$deviceId = (string) Str::uuid();
|
||||
$realSecret = Str::random(64);
|
||||
|
||||
UserTrustedDevice::create([
|
||||
'user_id' => $user->id,
|
||||
'device_id' => $deviceId,
|
||||
'token' => hash('sha256', $realSecret),
|
||||
'expires_at' => now()->addDays(30),
|
||||
]);
|
||||
|
||||
Session::put('auth.2fa_user_id', $user->id);
|
||||
Session::put('auth.2fa_code', '000000');
|
||||
Session::put('auth.2fa_expires_at', now()->addMinutes(10)->timestamp);
|
||||
|
||||
$this->withCookie('2fa_trust_device', $deviceId.'|wrong-secret')
|
||||
->get('/2fa')
|
||||
->assertOk();
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
Reference in New Issue
Block a user