view('auth.verify-email')); RateLimiter::for('login', function (Request $request) { $loginIdentifier = (string) $request->input('name'); // Changed from $request->email to $request->input('name') return Limit::perMinute(10)->by($loginIdentifier.$request->ip()); }); RateLimiter::for('two-factor', function (Request $request) { return Limit::perMinute(5)->by($request->session()->get('login.id')); }); // Rehash Cyclos salted sha256 passwords on first login Fortify::authenticateUsing(function (Request $request) { // Attempt to find the user by email or name. $user = User::where('email', $request->name) ->orWhere('name', $request->name) ->first(); if (!$user) { info('Auth failed: User not identified with login identifier: ' . $request->auth); return null; } if ($user->isRemoved()) { info('Auth failed: User ' . $user->name . ' is marked as removed (soft-deleted).'); return null; } // If maintenance mode is enabled, check if user has admin relationship if (isMaintenanceMode()) { $hasAdminRelation = $user->admins()->exists(); if (!$hasAdminRelation) { info('Auth failed: Maintenance mode is active and user ' . $user->name . ' does not have admin relationship.'); session()->flash('maintenance_mode_active', true); throw ValidationException::withMessages([ 'name' => __('Login is currently disabled due to site maintenance. Only administrator accounts can access the site at this time. Please try again later.'), ]); } info('Auth allowed during maintenance: User ' . $user->name . ' has admin relationship.'); } info('User identified: ' . $user->name . ' (ID: ' . $user->id . ') attempting login with identifier: ' . $request->auth); $passwordVerified = false; // Check for Cyclos password first if salt exists if (!empty($user->cyclos_salt)) { info('Attempting Cyclos password verification for user: ' . $user->name); $concatenated = $user->cyclos_salt . $request->password; $hashedInputPassword = hash("sha256", $concatenated); if (strtolower($hashedInputPassword) === strtolower($user->password)) { info('Cyclos password verified for user: ' . $user->name); // Prepare user model for update: rehash password and clear salt $user->password = Hash::make($request->password); $user->cyclos_salt = null; $passwordVerified = true; info('Cyclos password prepared for rehashing for user: ' . $user->name); } else { info('Cyclos password verification failed for user: ' . $user->name . '. Will attempt standard Laravel hash check.'); } } // If not verified by Cyclos, or if cyclos_salt was empty, try Laravel's default hash check if (!$passwordVerified && Hash::check($request->password, $user->password)) { info('Laravel password verified for user: ' . $user->name); $passwordVerified = true; } if ($passwordVerified) { info('Auth success for user: ' . $user->name); // Update last login details $now = Carbon::now()->toDateTimeString(); $user->last_login_at = $now; $user->last_login_ip = $request->getClientIp(); if (timebank_config('profile_inactive.re-activate_at_login')) { if (!$user->isActive()) { $user->inactive_at = null; $activated = true; } } // Save all changes (rehashed password, cleared salt, login details) $user->save(); if (isset($activated) && $activated) { info('User re-activated: ' . $user->name); } return $user; } info('Auth failed: Password mismatch for user: ' . $user->name . ' with identifier: ' . $request->auth); return null; }); } }