Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Traits\SwitchGuardTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
class UserLoginController extends Controller
|
||||
{
|
||||
use SwitchGuardTrait;
|
||||
|
||||
/**
|
||||
* Direct link to user login - can be used in emails
|
||||
* Handles the authentication flow:
|
||||
* 1. If user not authenticated -> redirect to user login with intended URL
|
||||
* 2. If user authenticated but wrong user -> 403 forbidden
|
||||
* 3. If correct user -> redirect to intended URL or main page
|
||||
* 4. Supports custom intended URL via query parameter
|
||||
*/
|
||||
public function directLogin(Request $request, $userId)
|
||||
{
|
||||
\Log::info('UserLoginController: directLogin called', [
|
||||
'user_id' => $userId,
|
||||
'request_url' => $request->fullUrl(),
|
||||
'all_params' => $request->all(),
|
||||
]);
|
||||
|
||||
// Validate user exists
|
||||
$user = User::find($userId);
|
||||
if (!$user) {
|
||||
abort(404, __('User not found'));
|
||||
}
|
||||
|
||||
// Get optional intended destination after successful login.
|
||||
// Validate it is a local URL to prevent open redirect attacks.
|
||||
$intendedParam = $request->query('intended');
|
||||
$intendedUrl = $this->validateLocalUrl($intendedParam, $request);
|
||||
|
||||
if (!$intendedUrl) {
|
||||
$intendedUrl = LaravelLocalization::localizeURL(
|
||||
route('main'),
|
||||
$user->lang_preference ?? config('app.fallback_locale')
|
||||
);
|
||||
}
|
||||
|
||||
// Check if user is authenticated on web guard
|
||||
\Log::info('UserLoginController: Checking authentication', [
|
||||
'is_authenticated' => Auth::guard('web')->check(),
|
||||
]);
|
||||
|
||||
if (!Auth::guard('web')->check()) {
|
||||
// User not logged in - redirect to user login with return URL
|
||||
$returnUrl = LaravelLocalization::localizeURL(
|
||||
route('user.direct-login', ['userId' => $userId]),
|
||||
$user->lang_preference ?? config('app.fallback_locale')
|
||||
);
|
||||
if ($intendedUrl) {
|
||||
$returnUrl .= '?intended=' . urlencode($intendedUrl);
|
||||
}
|
||||
|
||||
// Get the name parameter from the current request to pass along
|
||||
$nameParam = $request->query('name', $user->name);
|
||||
|
||||
\Log::info('UserLoginController: Redirecting to login', [
|
||||
'return_url' => $returnUrl,
|
||||
'intended_url' => $intendedUrl,
|
||||
'prefill_username' => $nameParam,
|
||||
]);
|
||||
|
||||
// Store in session for Laravel to redirect after login
|
||||
session()->put('url.intended', $returnUrl);
|
||||
|
||||
// Pass username as URL parameter to pre-fill login form
|
||||
// Use LaravelLocalization to ensure the parameter is preserved through localization
|
||||
$loginUrl = LaravelLocalization::localizeURL(
|
||||
route('login'),
|
||||
$user->lang_preference ?? config('app.fallback_locale')
|
||||
);
|
||||
$loginUrl .= '?name=' . urlencode($nameParam);
|
||||
|
||||
\Log::info('UserLoginController: Redirecting to login with name parameter', [
|
||||
'login_url' => $loginUrl,
|
||||
'username' => $nameParam,
|
||||
]);
|
||||
|
||||
return redirect()->to($loginUrl, 302, [], false);
|
||||
}
|
||||
|
||||
// User is authenticated - verify they are the correct user
|
||||
$authenticatedUser = Auth::guard('web')->user();
|
||||
|
||||
if ($authenticatedUser->id !== $user->id) {
|
||||
// Wrong user is logged in — log out all guards and redirect to login
|
||||
// so the recipient can authenticate as the correct profile
|
||||
foreach (['web', 'organization', 'bank', 'admin'] as $guard) {
|
||||
Auth::guard($guard)->logout();
|
||||
}
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
$returnUrl = route('user.direct-login', ['userId' => $userId]);
|
||||
if ($intendedUrl) {
|
||||
$returnUrl .= '?intended=' . urlencode($intendedUrl);
|
||||
}
|
||||
$nameParam = $request->query('name', $user->name);
|
||||
|
||||
session()->put('url.intended', $returnUrl);
|
||||
|
||||
$loginUrl = LaravelLocalization::localizeURL(
|
||||
route('login'),
|
||||
$user->lang_preference ?? config('app.fallback_locale')
|
||||
);
|
||||
$loginUrl .= '?name=' . urlencode($nameParam);
|
||||
|
||||
return redirect()->to($loginUrl, 302, [], false);
|
||||
}
|
||||
|
||||
// Re-activate profile if inactive
|
||||
if (timebank_config('profile_inactive.re-activate_at_login')) {
|
||||
if (!$user->isActive()) {
|
||||
$user->inactive_at = null;
|
||||
$user->save();
|
||||
info('User re-activated: ' . $user->name);
|
||||
}
|
||||
}
|
||||
|
||||
// Switch active guard back to 'web' (User profile).
|
||||
// This is a no-op if already on web, but ensures that users arriving from an
|
||||
// elevated profile (org/bank/admin) are switched back to their User profile.
|
||||
$wasElevated = session('active_guard', 'web') !== 'web';
|
||||
$this->switchGuard('web', $user);
|
||||
session([
|
||||
'activeProfileType' => get_class($user),
|
||||
'activeProfileId' => $user->id,
|
||||
'activeProfileName' => $user->name,
|
||||
'activeProfilePhoto' => $user->profile_photo_path ?? null,
|
||||
'activeProfileRoleLabel' => getProfileRoleLabel($user),
|
||||
'last_activity' => now(),
|
||||
'profile-switched-notification' => $wasElevated,
|
||||
]);
|
||||
|
||||
\Log::info('UserLoginController: Authenticated user verified, redirecting', [
|
||||
'user_id' => $authenticatedUser->id,
|
||||
'target_user_id' => $user->id,
|
||||
'intended_url' => $intendedUrl,
|
||||
]);
|
||||
|
||||
// Redirect to intended URL
|
||||
return redirect($intendedUrl);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user