enforce(RateLimiter::identifier(), 'login'); $passengerId = filterRequest('id'); $fingerprint = filterRequest('fingerPrint') ?? filterRequest('fingerprint'); $audience = filterRequest('aud'); if (empty($passengerId) || empty($fingerprint) || empty($audience)) { jsonError('Missing required parameters', 400); } $con = Database::get('main'); // التحقق من الجهاز من خلال البصمة $stmt = $con->prepare(' SELECT passengerID, fingerprint FROM tokens WHERE passengerID = :pid LIMIT 1 '); $stmt->execute([':pid' => $passengerId]); $row = $stmt->fetch(); $fpVerified = false; if ($row) { $fpPepper = getenv('FP_PEPPER') ?: ''; $storedFp = $row['fingerprint']; // دعم الطريقة الجديدة (hash) والقديمة (مباشر) if ($fpPepper) { $expectedHash = hash('sha256', $fingerprint . $fpPepper); $fpVerified = hash_equals($storedFp, $expectedHash); if (!$fpVerified) { $fpVerified = hash_equals($storedFp, $fingerprint); } } else { $fpVerified = hash_equals($storedFp, $fingerprint); } } // وقت رد ثابت لمنع Timing Attack $elapsed = microtime(true) - $startTime; if ($elapsed < 0.1) usleep((int)((0.1 - $elapsed) * 1000000)); if (!$fpVerified) { securityLog("Invalid login fingerprint", ['passengerId' => $passengerId]); jsonError('Invalid credentials', 401); } $limiter->reset(RateLimiter::identifier(), 'login'); $jwtService = new JwtService($redis); $jwt = $jwtService->generateAccessToken($passengerId, 'passenger', $audience, $fingerprint); // $refresh = $jwtService->generateRefreshToken($passengerId); jsonSuccess([ 'jwt' => $jwt, // 'refresh_token' => $refresh['token'], 'expires_in' => 3600 ]); } catch (PDOException $e) { securityLog("Login PDO Error", ['msg' => $e->getMessage()]); jsonError('Database error', 500); } catch (Exception $e) { securityLog("Login Error", ['msg' => $e->getMessage()]); jsonError('Server error', 500); }