129 lines
4.1 KiB
PHP
129 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Auth\LoginRequest;
|
|
use App\Models\User;
|
|
use App\Models\UserTrustedDevice;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\View\View;
|
|
|
|
class AuthenticatedSessionController extends Controller
|
|
{
|
|
/**
|
|
* Display the login view
|
|
*/
|
|
public function create(): View
|
|
{
|
|
return view('auth.login');
|
|
}
|
|
|
|
/**
|
|
* Handle an incoming authentication request
|
|
*/
|
|
public function store(LoginRequest $request): RedirectResponse
|
|
{
|
|
// Batch common auth settings
|
|
$settings = [
|
|
'2fa_enabled' => get_setting('two_factor_auth', false),
|
|
'allow_remember' => get_setting('session_allow_remember_me', true),
|
|
'remember_duration' => get_setting('session_remember_me_duration', 30),
|
|
'single_session' => get_setting('session_single_session', false),
|
|
];
|
|
|
|
$credentials = $request->only('email', 'password');
|
|
$remember = $settings['allow_remember'] && $request->boolean('remember');
|
|
|
|
// Check if 2FA is enabled globally
|
|
if ($settings['2fa_enabled']) {
|
|
if (Auth::validate($credentials)) {
|
|
$user = User::where('email', $request->email)->first();
|
|
|
|
// Check Trust Device bypass (Secure check)
|
|
$cookieValue = $request->cookie('2fa_trust_device');
|
|
$trustedBypass = false;
|
|
|
|
if ($cookieValue && str_contains($cookieValue, '|')) {
|
|
$parts = explode('|', $cookieValue, 2);
|
|
|
|
if (count($parts) === 2 && ! empty($parts[0]) && ! empty($parts[1])) {
|
|
[$uuid, $secret] = $parts;
|
|
|
|
$trust = UserTrustedDevice::where('user_id', $user->id)
|
|
->where('device_id', $uuid)
|
|
->where('expires_at', '>', now())
|
|
->first();
|
|
|
|
if ($trust && hash_equals($trust->token, hash('sha256', $secret))) {
|
|
$trustedBypass = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($trustedBypass) {
|
|
Auth::attempt($credentials, $remember);
|
|
$request->session()->regenerate();
|
|
$user->update(['last_session_id' => session()->getId()]);
|
|
|
|
return redirect()->intended(route('dashboard', absolute: false));
|
|
}
|
|
|
|
// Generate & Send OTP
|
|
TwoFactorController::generateAndSendOtp($user);
|
|
session(['auth.2fa_remember' => $remember]);
|
|
|
|
return redirect()->route('2fa.index');
|
|
}
|
|
}
|
|
|
|
// Authenticate user credentials normally
|
|
$request->authenticate();
|
|
$request->session()->regenerate();
|
|
|
|
/** @var User $user */
|
|
$user = Auth::user();
|
|
$user->update(['last_session_id' => session()->getId()]);
|
|
|
|
// Custom duration Remember Me
|
|
if ($remember) {
|
|
$minutes = 60 * 24 * $settings['remember_duration'];
|
|
cookie()->queue(
|
|
cookie(
|
|
name: Auth::getRecallerName(),
|
|
value: cookie()->get(Auth::getRecallerName()),
|
|
minutes: $minutes,
|
|
httpOnly: true,
|
|
secure: app()->environment('production'),
|
|
)
|
|
);
|
|
}
|
|
|
|
// SINGLE SESSION ENFORCEMENT
|
|
if ($settings['single_session']) {
|
|
Auth::logoutOtherDevices($request->password);
|
|
}
|
|
|
|
return redirect()->intended('/dashboard');
|
|
}
|
|
|
|
/**
|
|
* Destroy an authenticated session
|
|
*/
|
|
public function destroy(Request $request): RedirectResponse
|
|
{
|
|
Auth::guard('web')->logout();
|
|
|
|
// Invalidate session for security
|
|
$request->session()->invalidate();
|
|
|
|
// Regenerate CSRF token
|
|
$request->session()->regenerateToken();
|
|
|
|
// Redirect to homepage
|
|
return redirect('/');
|
|
}
|
|
}
|