namespace App\Http\Controllers\Web; use App\Http\Controllers\Controller; use App\Http\Requests\Auth\LoginRequest; use App\Http\Requests\Auth\RegisterRequest; use App\Http\Requests\Auth\ForgotPasswordRequest; use App\Http\Requests\Auth\ResetPasswordRequest; use App\Models\User; use App\Services\Auth\TwoFactorService; use App\Services\Notification\EmailService; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Password; use Illuminate\Support\Str; use Laravel\Socialite\Facades\Socialite; class AuthController extends Controller { protected $twoFactorService; protected $emailService; public function __construct(TwoFactorService $twoFactorService, EmailService $emailService) { $this->twoFactorService = $twoFactorService; $this->emailService = $emailService; } // Show login form public function showLoginForm() { if (Auth::check()) { return redirect()->route('dashboard'); } return view('web.auth.login'); } // Handle login public function login(LoginRequest $request) { $credentials = $request->only('email', 'password'); $remember = $request->boolean('remember'); // Check rate limiting $this->checkTooManyFailedAttempts(); if (Auth::attempt($credentials, $remember)) { $user = Auth::user(); // Check if user is active if (!$user->isActive()) { Auth::logout(); return back()->withErrors([ 'email' => 'Your account is ' . $user->status . '. Please contact support.', ]); } // Check if 2FA is enabled if ($user->two_factor_enabled) { $request->session()->put('2fa:user:id', $user->id); Auth::logout(); return redirect()->route('2fa.challenge'); } // Regenerate session $request->session()->regenerate(); // Log the login $user->logLogin('success'); $user->updateLastLogin($request->ip()); // Clear failed attempts $this->clearLoginAttempts($request); return redirect()->intended(route('dashboard')); } // Log failed attempt $this->incrementLoginAttempts($request); $user = User::where('email', $request->email)->first(); if ($user) { $user->logLogin('failed'); } return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ])->onlyInput('email'); } // Show registration form public function showRegistrationForm(Request $request) { if (Auth::check()) { return redirect()->route('dashboard'); } $referralCode = $request->get('ref'); return view('web.auth.register', compact('referralCode')); } // Handle registration public function register(RegisterRequest $request) { $user = User::create([ 'username' => $request->username, 'email' => $request->email, 'password' => Hash::make($request->password), 'first_name' => $request->first_name, 'last_name' => $request->last_name, 'phone' => $request->phone, 'country' => $request->country, 'referred_by' => $this->getReferrerId($request->referral_code), 'status' => 'active', ]); // Generate referral code $user->generateReferralCode(); // Send verification email $user->sendEmailVerificationNotification(); // Log the registration $user->logActivity('Registered new account', ['method' => 'email'], 'register'); // Log in the user Auth::login($user); $user->logLogin('success'); $user->updateLastLogin($request->ip()); // Send welcome notification $this->emailService->sendWelcomeEmail($user); return redirect()->route('dashboard') ->with('success', 'Registration successful! Please verify your email address.'); } // Handle logout public function logout(Request $request) { $user = Auth::user(); if ($user) { $user->logLogout(); } Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/'); } // Show forgot password form public function showForgotForm() { return view('web.auth.forgot-password'); } // Handle forgot password public function forgotPassword(ForgotPasswordRequest $request) { $status = Password::sendResetLink( $request->only('email') ); if ($status === Password::RESET_LINK_SENT) { return back()->with('success', __($status)); } return back()->withErrors(['email' => __($status)]); } // Show reset password form public function showResetForm($token) { return view('web.auth.reset-password', ['token' => $token]); } // Handle reset password public function resetPassword(ResetPasswordRequest $request) { $status = Password::reset( $request->only('email', 'password', 'password_confirmation', 'token'), function ($user, $password) { $user->forceFill([ 'password' => Hash::make($password), 'remember_token' => Str::random(60), ])->save(); $user->logActivity('Password reset completed', [], 'password_reset'); } ); if ($status === Password::PASSWORD_RESET) { return redirect()->route('login')->with('success', __($status)); } return back()->withErrors(['email' => [__($status)]]); } // Show 2FA challenge form public function showTwoFactorChallenge() { if (!session()->has('2fa:user:id')) { return redirect()->route('login'); } return view('web.auth.two-factor-challenge'); } // Handle 2FA challenge public function twoFactorChallenge(Request $request) { $request->validate([ 'code' => 'required|string', ]); $userId = $request->session()->get('2fa:user:id'); $user = User::findOrFail($userId); if ($this->twoFactorService->verify($user, $request->code)) { Auth::login($user); $request->session()->forget('2fa:user:id'); $request->session()->regenerate(); $user->logLogin('success'); $user->updateLastLogin($request->ip()); return redirect()->intended(route('dashboard')); } return back()->withErrors(['code' => 'The provided code is invalid.']); } // Verify email public function verifyEmail($id, $hash) { $user = User::findOrFail($id); if (!hash_equals((string) $hash, sha1($user->getEmailForVerification()))) { return redirect()->route('verification.notice') ->with('error', 'Invalid verification link.'); } if ($user->hasVerifiedEmail()) { return redirect()->route('dashboard') ->with('info', 'Email already verified.'); } $user->markEmailAsVerified(); $user->logActivity('Email verified', [], 'email_verify'); return redirect()->route('dashboard') ->with('success', 'Email verified successfully!'); } // Resend verification email public function resendVerification(Request $request) { $user = Auth::user(); if ($user->hasVerifiedEmail()) { return redirect()->route('dashboard') ->with('info', 'Email already verified.'); } $user->sendEmailVerificationNotification(); return back()->with('success', 'Verification email sent.'); } // Redirect to Google public function redirectToGoogle() { return Socialite::driver('google')->redirect(); } // Handle Google callback public function handleGoogleCallback(Request $request) { try { $googleUser = Socialite::driver('google')->user(); $user = User::where('email', $googleUser->email)->first(); if (!$user) { // Create new user $user = User::create([ 'username' => strtolower(str_replace(' ', '_', $googleUser->name)) . '_' . uniqid(), 'email' => $googleUser->email, 'password' => Hash::make(Str::random(24)), 'first_name' => $googleUser->user['given_name'] ?? $googleUser->name, 'last_name' => $googleUser->user['family_name'] ?? '', 'email_verified_at' => now(), 'status' => 'active', ]); $user->generateReferralCode(); $user->logActivity('Registered with Google', [], 'register'); } // Log in the user Auth::login($user); $user->logLogin('success'); $user->updateLastLogin($request->ip()); return redirect()->intended(route('dashboard')); } catch (\Exception $e) { return redirect()->route('login') ->with('error', 'Google login failed. Please try again.'); } } // Rate limiting methods protected function checkTooManyFailedAttempts() { if ($this->hasTooManyLoginAttempts()) { $this->fireLockoutEvent(); return $this->sendLockoutResponse(); } } protected function hasTooManyLoginAttempts() { return app('limiter')->tooManyAttempts( $this->throttleKey(), $this->maxAttempts() ); } protected function incrementLoginAttempts($request) { app('limiter')->hit( $this->throttleKey($request), $this->decayMinutes() ); } protected function clearLoginAttempts($request) { app('limiter')->clear($this->throttleKey($request)); } protected function throttleKey($request = null) { $request = $request ?: request(); return Str::lower($request->input('email')) . '|' . $request->ip(); } protected function maxAttempts() { return 5; } protected function decayMinutes() { return 30; } protected function getReferrerId($code) { if (!$code) { return null; } $referrer = User::where('referral_code', $code)->first(); return $referrer ? $referrer->id : null; } }