input('email') ?? $request->input('login'); if (!$rawLogin) { return null; } Log::info("LOGIN: Attempting login for '$rawLogin'"); $lowerLogin = strtolower($rawLogin); $loginHash = hash('sha256', $rawLogin); $lowerLoginHash = hash('sha256', $lowerLogin); $user = User::where(function ($query) use ($rawLogin, $lowerLogin, $loginHash, $lowerLoginHash) { $query->where('email', $rawLogin) // Case-sensitive match ->orWhere('username', $rawLogin) // Case-sensitive match ->orWhereRaw('LOWER(email) = ?', [$lowerLogin]) // Case-insensitive match ->orWhereRaw('LOWER(username) = ?', [$lowerLogin]) // Case-insensitive match ->orWhere('email_index', $loginHash) // Original hash match ->orWhere('email_index', $lowerLoginHash) // Lowercase hash match ->orWhere('username_index', $loginHash) // Original hash match ->orWhere('username_index', $lowerLoginHash); // Lowercase hash match })->first(); if ($user) { Log::info("LOGIN: User found (ID: {$user->id}). Checking password..."); $passwordMatches = false; // 1. Standard Bcrypt check if (Hash::check($request->password, $user->password)) { Log::info("LOGIN: Password matched using Bcrypt (Correct)."); $passwordMatches = true; } // 2. Plaintext check (and upgrade) elseif ($user->password === $request->password) { Log::warning("LOGIN: Plaintext password matched for User ID {$user->id}. Upgrading hash now."); $passwordMatches = true; $user->forceFill(['password' => Hash::make($request->password)])->save(); } // 3. SHA256 check (and upgrade) elseif (hash('sha256', $request->password) === $user->password) { Log::warning("LOGIN: SHA256 password matched for User ID {$user->id}. This is insecure. Upgrading hash now."); $passwordMatches = true; $user->forceFill(['password' => Hash::make($request->password)])->save(); } // 4. MD5 check (and upgrade) elseif (hash('md5', $request->password) === $user->password) { Log::warning("LOGIN: MD5 password matched for User ID {$user->id}. This is insecure. Upgrading hash now."); $passwordMatches = true; $user->forceFill(['password' => Hash::make($request->password)])->save(); } if ($passwordMatches) { Log::info("LOGIN: Password check successful for User ID {$user->id}."); if (UserRestriction::where('user_id', $user->id)->where('type', 'account_ban')->active()->exists()) { Log::warning("LOGIN: Login blocked for banned User ID {$user->id}."); return null; } $user->forceFill([ 'last_login_at' => now(), 'last_login_ip' => $request->ip(), 'last_login_user_agent' => $request->userAgent() ?? '', ])->save(); if ($user->stats) { $user->stats()->increment('total_logins'); } return $user; } else { Log::error("LOGIN: All password checks failed for User ID {$user->id}."); } } else { Log::error("LOGIN: User with identifier '$rawLogin' not found in database."); } return null; }); $this->configureActions(); $this->configureViews(); $this->configureRateLimiting(); } private function configureActions(): void { Fortify::resetUserPasswordsUsing(ResetUserPassword::class); Fortify::createUsersUsing(CreateNewUser::class); } private function configureViews(): void { Fortify::loginView(fn (Request $request) => Inertia::render('auth/Login', [ 'canResetPassword' => Features::enabled(Features::resetPasswords()), 'canRegister' => Features::enabled(Features::registration()), 'status' => $request->session()->get('status'), ])); Fortify::resetPasswordView(fn (Request $request) => Inertia::render('auth/ResetPassword', [ 'email' => $request->email, 'token' => $request->route('token'), ])); Fortify::requestPasswordResetLinkView(fn (Request $request) => Inertia::render('auth/ForgotPassword', [ 'status' => $request->session()->get('status'), ])); Fortify::verifyEmailView(function (Request $request) { $user = $request->user(); $expire = (int) Config::get('auth.verification.expire', 60); $verificationUrl = null; if ($user) { $verificationUrl = URL::temporarySignedRoute( 'verification.verify', now()->addMinutes($expire), [ 'id' => $user->getKey(), 'hash' => sha1($user->getEmailForVerification()), ] ); } $cacheKey = $user ? 'email_verify_code:'.$user->getKey() : null; $hasCode = $cacheKey ? !is_null(Cache::get($cacheKey)) : false; return Inertia::render('auth/VerifyEmail', [ 'status' => $request->session()->get('status'), 'verificationUrl' => $verificationUrl, 'hasCode' => $hasCode, ]); }); Fortify::registerView(fn () => Inertia::render('auth/Register')); Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/TwoFactorChallenge')); Fortify::confirmPasswordView(fn () => Inertia::render('auth/ConfirmPassword')); } private function configureRateLimiting(): void { RateLimiter::for('two-factor', function (Request $request) { return Limit::perMinute(5)->by($request->session()->get('login.id')); }); RateLimiter::for('login', function (Request $request) { $username = (string) $request->input(Fortify::username()); $throttleKey = Str::lower($username).'|'.$request->ip(); return Limit::perMinute(5)->by($throttleKey); }); } }