71 lines
2.1 KiB
PHP
71 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Auth;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\Validate;
|
|
use Livewire\Component;
|
|
use PragmaRX\Google2FAQRCode\Google2FA;
|
|
|
|
#[Layout('layouts.auth')]
|
|
class TwoFactorChallenge extends Component
|
|
{
|
|
#[Validate('required|string')]
|
|
public string $code = '';
|
|
|
|
public function mount()
|
|
{
|
|
if (! session()->has('2fa.user')) {
|
|
return $this->redirect(route('login'), navigate: true);
|
|
}
|
|
}
|
|
|
|
public function verify()
|
|
{
|
|
$this->validate();
|
|
|
|
$key = 'two-factor:'.md5(session('2fa.user').'|'.request()->ip());
|
|
|
|
if (RateLimiter::tooManyAttempts($key, 5)) {
|
|
throw ValidationException::withMessages([
|
|
'code' => __('auth.too_many_attempts', ['seconds' => RateLimiter::availableIn($key)]),
|
|
]);
|
|
}
|
|
|
|
$user = User::find(session('2fa.user'));
|
|
|
|
if (! $user || ! $user->hasTwoFactorEnabled()) {
|
|
session()->forget(['2fa.user', '2fa.remember']);
|
|
throw ValidationException::withMessages(['code' => __('auth.session_expired')]);
|
|
}
|
|
|
|
// Accept the TOTP code, or fall back to a one-time backup (recovery) code.
|
|
$valid = (new Google2FA)->verifyKey($user->two_factor_secret, preg_replace('/\s+/', '', $this->code))
|
|
|| $user->useRecoveryCode($this->code);
|
|
|
|
if (! $valid) {
|
|
RateLimiter::hit($key, 60);
|
|
throw ValidationException::withMessages(['code' => __('auth.invalid_code')]);
|
|
}
|
|
|
|
RateLimiter::clear($key);
|
|
|
|
$remember = (bool) session('2fa.remember');
|
|
session()->forget(['2fa.user', '2fa.remember']);
|
|
|
|
Auth::login($user, $remember);
|
|
session()->regenerate();
|
|
|
|
return $this->redirectIntended(route('dashboard'), navigate: true);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.auth.two-factor-challenge')->title(__('auth.title_challenge'));
|
|
}
|
|
}
|