Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config; // Import Config facade
use Illuminate\Support\Facades\Session;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class CheckProfileInactivity
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
// Only proceed if a user is authenticated
if (!Auth::check()) {
Session::forget('last_activity'); // Clear timestamp if user logs out
return $next($request); // Pass the request to the next middleware - route-level auth middleware will handle redirect
}
// When user is authenticated
$activeProfileType = Session::get('activeProfileType', \App\Models\User::class); // Default to User class if not set
// Initialize active profile if not set (happens after login)
if (!Session::has('activeProfileId')) {
$user = Auth::guard('web')->user();
if ($user) {
Session::put([
'activeProfileType' => \App\Models\User::class,
'activeProfileId' => $user->id,
'activeProfileName' => $user->name,
'activeProfilePhoto' => $user->profile_photo_path,
]);
}
}
$lastActivity = Session::get('last_activity');
// If last_activity is not set, initialize it and continue (first request after login)
if (!$lastActivity) {
Session::put('last_activity', now());
return $next($request);
}
// Check base session timeout first (this should never exceed SESSION_LIFETIME)
// This prevents profile-specific timeouts from keeping sessions alive beyond the base session lifetime
$baseSessionLifetime = Config::get('session.lifetime', 120); // minutes
$minutesSinceActivity = now()->diffInMinutes($lastActivity);
// If base session has expired, force logout regardless of profile type
if ($minutesSinceActivity >= $baseSessionLifetime) {
$user = Auth::guard('web')->user();
Auth::guard('web')->logout();
Session::invalidate();
Session::regenerateToken();
// For AJAX requests, return a JSON response indicating logout
if ($request->expectsJson() || $request->ajax()) {
return response()->json([
'message' => __('Your session timed out due to inactivity. Please log in again.'),
'action' => 'logout',
'redirect_url' => LaravelLocalization::localizeUrl('/login')
], 419); // 419 Authentication Timeout
} else {
// For standard browser requests, redirect to login
$loginUrl = LaravelLocalization::localizeUrl('/login');
return redirect()->to($loginUrl)
->with('warning', __('Your session timed out due to inactivity. Please log in again.'));
}
}
// Get the specific timeout for the current profile type, or use the default of 120 min.
$configuredTimeout = timebank_config('profile_timeouts.' . $activeProfileType, timebank_config('profile_timeout_default', 120));
// Profile-specific timeout cannot exceed base session lifetime
// This ensures elevated profiles timeout at or before the base session expiration
$timeoutMinutes = min($configuredTimeout, $baseSessionLifetime);
// Log when timeout is being capped for debugging purposes
if ($configuredTimeout > $baseSessionLifetime) {
\Log::info('Profile timeout capped by SESSION_LIFETIME', [
'profile_type' => class_basename($activeProfileType),
'configured_timeout' => $configuredTimeout,
'session_lifetime' => $baseSessionLifetime,
'effective_timeout' => $timeoutMinutes,
]);
}
// Check if the timestamp exists and if the inactivity period has passed
if ($minutesSinceActivity >= $timeoutMinutes) {
$user = Auth::guard('web')->user();
// Check if the current active profile is already the User profile
if ($activeProfileType === \App\Models\User::class) {
// If the active profile is User and their session expires, log them out
Auth::guard('web')->logout();
Session::invalidate();
Session::regenerateToken();
// For AJAX requests, return a JSON response indicating logout
if ($request->expectsJson() || $request->ajax()) {
return response()->json([
'message' => __('Your session timed out due to inactivity. Please log in again.'),
'action' => 'logout', // Indicate a full logout
'redirect_url' => LaravelLocalization::localizeUrl('/login') // Provide login URL
], 419); // 419 Authentication Timeout
} else {
// For standard browser requests, redirect to login
$loginUrl = LaravelLocalization::localizeUrl('/login');
return redirect()->to($loginUrl)
->with('warning', __('Your session timed out due to inactivity. Please log in again.'));
}
} else {
// If the active profile is an elevated profile (Bank, Admin, etc.), switch back to User profile
Session::put([
'activeProfileType' => \App\Models\User::class,
'activeProfileId' => $user->id,
'activeProfileName' => $user->name,
'activeProfilePhoto' => $user->profile_photo_path,
'profile-switched-notification' => true,
]);
session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component
Session::forget('last_activity'); // Clear the timestamp
event(new \App\Events\ProfileSwitchEvent($user));
// Check if the request expects JSON (common for AJAX) or is an AJAX request
if ($request->expectsJson() || $request->ajax()) {
session(['notification.alert' => 'Your previous profile session timed out due to inactivity.']); // Will become a translation key in notification component
// Get the user's locale from the session (set by localization middleware)
$userLocale = Session::get('locale', config('app.fallback_locale'));
// Use LaravelLocalization to get the full, localized URL
$redirectUrl = LaravelLocalization::getURLFromRouteNameTranslated($userLocale, 'routes.main');
Session::save();
// Return a JSON response indicating timeout, use 419 status code
return response()->json([
'message' => __('Your previous profile session timed out due to inactivity.'),
'action' => 'redirect', // Change action name to 'redirect'
'redirect_url' => $redirectUrl // <-- Add URL to payload
], 419); // 419 Authentication Timeout
} else {
// For standard browser requests, perform the redirect with flash message
$mainUrl = LaravelLocalization::localizeUrl('/main-page');
return redirect()->to($mainUrl)
->with('warning', __('Your previous profile session timed out due to inactivity.'));
}
}
}
// Update the activity timestamp on relevant requests
// Exclude background heartbeats but allow user-initiated Livewire interactions
$isLivewireUpdate = $request->is(['*/livewire/update', 'livewire/update']);
$isUserInteraction = $isLivewireUpdate && $request->has('components');
if (!$request->is(['api/messenger/heartbeat']) && (!$isLivewireUpdate || $isUserInteraction)) {
Session::put('last_activity', now());
}
return $next($request); // Ensure the request is passed to the next middleware
}
}