Update: 2026-06-16 02:14:34
This commit is contained in:
@@ -29,7 +29,8 @@ class RateLimiter
|
|||||||
public function check(string $identifier, string $type = 'api'): bool
|
public function check(string $identifier, string $type = 'api'): bool
|
||||||
{
|
{
|
||||||
if (!$this->redis) {
|
if (!$this->redis) {
|
||||||
return true; // بدون Redis نمرر (fallback)
|
// HIGH-01 FIX: fallback مع ملف بدلاً من تمرير كل الطلبات
|
||||||
|
return $this->fileBasedCheck($identifier, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit = self::LIMITS[$type] ?? self::LIMITS['api'];
|
$limit = self::LIMITS[$type] ?? self::LIMITS['api'];
|
||||||
@@ -77,6 +78,47 @@ class RateLimiter
|
|||||||
{
|
{
|
||||||
if ($this->redis) {
|
if ($this->redis) {
|
||||||
$this->redis->del("rate:{$type}:{$identifier}");
|
$this->redis->del("rate:{$type}:{$identifier}");
|
||||||
|
} else {
|
||||||
|
// HIGH-01: مسح ملف الفل باك عند إعادة التعيين
|
||||||
|
$key = self::sanitizeKey("rate:{$type}:{$identifier}");
|
||||||
|
$tmpFile = sys_get_temp_dir() . "/rate_{$key}.json";
|
||||||
|
if (file_exists($tmpFile)) {
|
||||||
|
@unlink($tmpFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Fallback باستخدام ملفات مؤقتة عند تعطل Redis ───────────
|
||||||
|
private function fileBasedCheck(string $identifier, string $type): bool
|
||||||
|
{
|
||||||
|
$limit = self::LIMITS[$type] ?? self::LIMITS['api'];
|
||||||
|
$window = $limit['window'];
|
||||||
|
$max = $limit['requests'];
|
||||||
|
|
||||||
|
$key = self::sanitizeKey("rate:{$type}:{$identifier}");
|
||||||
|
$tmpFile = sys_get_temp_dir() . "/rate_{$key}.json";
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
if (file_exists($tmpFile)) {
|
||||||
|
$data = json_decode(file_get_contents($tmpFile), true) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// تنظيف النوافذ القديمة
|
||||||
|
$data = array_filter($data, fn($ts) => $ts > ($now - $window));
|
||||||
|
|
||||||
|
if (count($data) >= $max) {
|
||||||
|
error_log("[RATE_LIMIT_FB] File-based block: $identifier | type: $type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[] = $now;
|
||||||
|
file_put_contents($tmpFile, json_encode($data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function sanitizeKey(string $key): string
|
||||||
|
{
|
||||||
|
return preg_replace('/[^a-zA-Z0-9_\-:]/', '_', $key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,11 @@ class EncryptionHelper {
|
|||||||
|
|
||||||
public function decryptBinary($data) {
|
public function decryptBinary($data) {
|
||||||
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||||
|
// CRIT-07 FIX: التحقق من فشل openssl_decrypt
|
||||||
|
if ($decrypted === false) {
|
||||||
|
error_log('[CRIT-07] openssl_decrypt failed in decryptBinary');
|
||||||
|
throw new Exception('Decryption failed');
|
||||||
|
}
|
||||||
return $decrypted;
|
return $decrypted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ try {
|
|||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$errorMsg = "❌ [Cleanup Cron] Error: " . $e->getMessage();
|
$errorMsg = "❌ [Cleanup Cron] Error: " . $e->getMessage();
|
||||||
error_log($errorMsg);
|
error_log($errorMsg);
|
||||||
echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
|
error_log("[cron_ride_timeout] Error: " . $e->getMessage());
|
||||||
|
echo json_encode(["status" => "failure", "message" => "An internal error occurred."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -73,7 +73,8 @@ try {
|
|||||||
echo json_encode(["status" => "success", "data" => $finalData]);
|
echo json_encode(["status" => "success", "data" => $finalData]);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
|
error_log("[getRealTimeHeatmap] Error: " . $e->getMessage());
|
||||||
|
echo json_encode(["status" => "failure", "message" => "An internal error occurred."]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToGrid(&$grid, $lat, $lng, $precision, $weight) {
|
function addToGrid(&$grid, $lat, $lng, $precision, $weight) {
|
||||||
|
|||||||
@@ -174,6 +174,6 @@ try {
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("API Error: " . $e->getMessage());
|
error_log("API Error: " . $e->getMessage());
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]);
|
echo json_encode(["status" => "failure", "message" => "An internal server error occurred."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -143,6 +143,6 @@ try {
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("API Error: " . $e->getMessage());
|
error_log("API Error: " . $e->getMessage());
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]);
|
echo json_encode(["status" => "failure", "message" => "An internal server error occurred."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -88,6 +88,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
|
error_log("[getRideStatusFromStartApp] Error: " . $e->getMessage());
|
||||||
|
echo json_encode(["status" => "failure", "message" => "An internal error occurred."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -88,6 +88,11 @@ class EncryptionHelper {
|
|||||||
|
|
||||||
public function decryptBinary($data) {
|
public function decryptBinary($data) {
|
||||||
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||||
|
// CRIT-07 FIX: التحقق من فشل openssl_decrypt
|
||||||
|
if ($decrypted === false) {
|
||||||
|
error_log('[CRIT-07] openssl_decrypt failed in decryptBinary');
|
||||||
|
throw new Exception('Decryption failed');
|
||||||
|
}
|
||||||
return $decrypted;
|
return $decrypted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ header('Content-Type: application/json');
|
|||||||
header("Access-Control-Allow-Origin: https://wallet.sefer.live"); // Replace * with your Flutter app's origin
|
header("Access-Control-Allow-Origin: https://wallet.sefer.live"); // Replace * with your Flutter app's origin
|
||||||
header("Access-Control-Allow-Methods: POST, OPTIONS");
|
header("Access-Control-Allow-Methods: POST, OPTIONS");
|
||||||
header("Access-Control-Allow-Headers: Content-Type, Authorization");
|
header("Access-Control-Allow-Headers: Content-Type, Authorization");
|
||||||
|
// MED FIX: إضافة Security Headers
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
header('X-Frame-Options: DENY');
|
||||||
|
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
|
||||||
|
header("Referrer-Policy: strict-origin-when-cross-origin");
|
||||||
|
header("X-XSS-Protection: 1; mode=block");
|
||||||
|
|
||||||
// Handle preflight OPTIONS requests
|
// Handle preflight OPTIONS requests
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
@@ -123,13 +129,13 @@ $hmac = hash_hmac('sha256', $id, getenv('SECRET_KEY_HMAC'));
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
// Handle input validation errors
|
// HIGH-05 FIX: لا تكشف رسائل الخطأ من الاستثناءات مباشرة
|
||||||
http_response_code(400); // Bad Request - Client-side error
|
error_log("Input validation error: " . $e->getMessage());
|
||||||
// error_log("Input validation error: " . $e->getMessage()); // Log for debugging
|
http_response_code(400);
|
||||||
echo json_encode(['error' => $e->getMessage()]); // Specific error message
|
echo json_encode(['error' => 'Invalid request parameters.']);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// Handle other exceptions (e.g., JWT encoding errors)
|
// HIGH-05 FIX: لا تكشف رسائل الخطأ الداخلية
|
||||||
http_response_code(500); // Internal Server Error
|
error_log("Server error: " . $e->getMessage());
|
||||||
// error_log("Server error: " . $e->getMessage()); // Log for debugging
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'An unexpected error occurred.']); // Generic message
|
echo json_encode(['error' => 'An unexpected error occurred.']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,14 +70,18 @@ try {
|
|||||||
$user = $stmt->fetch();
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
// إذا لم يكن موجوداً، نتحقق من كلمة السر العامة للأدمن كخيار أخير
|
// ⚠️ CRIT-01 FIX: إزالة backdoor الدخول بكلمة سر plaintext
|
||||||
if ($id === 'admin' && $password === $passwordnewpassenger) {
|
// لا يمكن الدخول إلا عبر مستخدمين مسجلين في قاعدة البيانات
|
||||||
// السماح بالدخول كأدمن عام
|
http_response_code(403);
|
||||||
} else {
|
echo json_encode(['error' => 'User not found']);
|
||||||
http_response_code(403);
|
exit;
|
||||||
echo json_encode(['error' => 'User not found']);
|
}
|
||||||
exit;
|
|
||||||
}
|
// التحقق من كلمة السر باستخدام password_verify (آمن)
|
||||||
|
if (!password_verify($password, $user['password'])) {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Invalid credentials']);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- إنشاء JWT ---
|
// --- إنشاء JWT ---
|
||||||
@@ -102,6 +106,8 @@ try {
|
|||||||
http_response_code(200);
|
http_response_code(200);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
// HIGH-05 FIX: لا تكشف رسائل الخطأ التفصيلية
|
||||||
|
error_log('[loginWalletAdmin] Error: ' . $e->getMessage());
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'Unexpected error occurred: ' . $e->getMessage()]);
|
echo json_encode(['error' => 'An internal error occurred. Please try again later.']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,6 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Error in cliq verify: " . $e->getMessage());
|
error_log("Error in cliq verify: " . $e->getMessage());
|
||||||
echo json_encode(["status" => "error", "message" => "Server error: " . $e->getMessage()]);
|
echo json_encode(["status" => "error", "message" => "Server error occurred."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Generate unique tokens
|
// 2. Generate unique tokens
|
||||||
$paymentID1 = "budget2pt_" . time() . rand(1000, 9999);
|
$paymentID1 = "budget2pt_" . time() . bin2hex(random_bytes(4));
|
||||||
$paymentID2 = "pt2budget_" . time() . rand(1000, 9999);
|
$paymentID2 = "pt2budget_" . time() . bin2hex(random_bytes(4));
|
||||||
$token1 = md5(uniqid("b1", true));
|
$token1 = bin2hex(random_bytes(32));
|
||||||
$token2 = md5(uniqid("b2", true));
|
$token2 = bin2hex(random_bytes(32));
|
||||||
|
|
||||||
// 3. Deduct from budget (payments)
|
// 3. Deduct from budget (payments)
|
||||||
$deductAmount = -$amount;
|
$deductAmount = -$amount;
|
||||||
@@ -62,6 +62,7 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$con->rollBack();
|
$con->rollBack();
|
||||||
echo json_encode(['status' => 'error', 'message' => 'Database transaction failed: ' . $e->getMessage()]);
|
error_log('[convertBudgetToPoints] Error: ' . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred.']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$con->rollBack();
|
$con->rollBack();
|
||||||
echo json_encode(['status' => 'error', 'message' => 'Database transaction failed: ' . $e->getMessage()]);
|
error_log('[transfer] Error: ' . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred.']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
Reference in New Issue
Block a user