checkWebAuth() || $this->checkJwtAuth($request); if (!$isAuthenticated && $request->filled('tracking')) { $trackingCode = $this->validateTrackingCode($request->get('tracking')); if ($trackingCode) { $this->trackClick($trackingCode); } } return $next($request); } /** * Validate and sanitize tracking code * * @param mixed $code * @return string|null */ private function validateTrackingCode($code): ?string { if (!is_string($code)) { return null; } // Trim whitespace $code = trim($code); // Check length (max 255 chars based on database schema) if (strlen($code) > 255 || strlen($code) < 1) { return null; } // Only allow alphanumeric characters, hyphens, and underscores // This matches typical affiliate code formats if (!preg_match('/^[a-zA-Z0-9_-]+$/', $code)) { return null; } return $code; } /** * Check if user is authenticated via WEB session */ private function checkWebAuth(): bool { try { if (Auth::guard('web')->check()) { return true; } // fallback session check foreach (Session::all() as $key => $value) { if (strpos($key, 'login_web_') === 0 && !empty($value)) { return true; } } } catch (\Exception $e) { Log::warning('AffiliateClickMiddleware: Web auth error', ['error' => $e->getMessage()]); } return false; } /** * Check if user is authenticated via JWT token */ private function checkJwtAuth(Request $request): bool { try { $token = $this->getBearerToken($request) ?? $request->get('token') ?? $request->cookie('access_token') ?? $request->cookie('user-token'); if (!$token) { return false; } JWTAuth::setToken($token); $user = JWTAuth::authenticate(); if ($user) { return true; } } catch (\Exception $e) { Log::debug('AffiliateClickMiddleware: JWT invalid', ['error' => $e->getMessage()]); } return false; } /** * Extract Bearer token */ private function getBearerToken(Request $request): ?string { if (!$request->hasHeader('Authorization')) return null; return preg_match('/Bearer\s+(.*)$/i', $request->header('Authorization'), $m) ? $m[1] : null; } /** * Track affiliate click once per session */ private function trackClick(string $trackingCode): void { // Use a single session key with an array to prevent session bloat $trackedClicks = Session::get('affiliate_clicks_tracked', []); // Check if this code has already been tracked in this session if (in_array($trackingCode, $trackedClicks)) { return; // Already tracked } // Execute tracking app(TracksAffiliateClick::class)->execute($trackingCode); // Add to tracked list $trackedClicks[] = $trackingCode; // Limit array size to prevent DoS (keep only last 10 clicks) if (count($trackedClicks) > 10) { $trackedClicks = array_slice($trackedClicks, -10); } Session::put('affiliate_clicks_tracked', $trackedClicks); } }