Files
Siro/backend/connect.php
T

112 lines
5.0 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// ============================================================
// connect.php (النسخة الحديثة)
// بوابة التطبيقات (تستلزم JWT)
// ============================================================
require_once __DIR__ . '/core/bootstrap.php';
// --------- تحقق من تطابق المنطقة (Region Mismatch Guard) ---------
$requestHost = $_SERVER['HTTP_HOST'] ?? '';
$appDomain = getenv('APP_DOMAIN') ?: '';
if (!empty($appDomain) && !empty($requestHost) && strtolower($requestHost) !== strtolower($appDomain)) {
if ($requestHost !== 'localhost' && !preg_match('/^127\.0\.0\./', $requestHost)) {
http_response_code(400);
exit(json_encode([
'status' => 'failure',
'error_code' => 'REGION_MISMATCH',
'message' => "Region mismatch: Request host '$requestHost' does not match server domain '$appDomain'."
]));
}
}
require_once __DIR__ . '/functions.php';
// 1. Rate Limiting and JWT Authentication
$limiter = new RateLimiter($redis);
$limiter->enforce(RateLimiter::identifier(), 'api');
$jwtService = new JwtService($redis);
$decoded = $jwtService->authenticate();
// متغيرات مساعدة للمطور
$user_id = $decoded->user_id ?? null;
$role = $decoded->role ?? 'passenger';
// ============================================================
// 2. بوّابة صلاحيات افتراضية لمسار /Admin
// ============================================================
// النموذج السابق كان «آمن إن تذكّرت»: كل نقطة تحت Admin/ تفحص الدور بنفسها،
// ومن يُغفل الفحص يصبح مكشوفاً. وقد وُجد فعلاً أن getPassengerDetails.php
// و getPassengerDetailsByPassengerID.php و getPassengerbyEmail.php كانت بلا
// أي فحص، فكان أي حامل JWT صالح — بما فيه راكب عادي — يقرأ بيانات ركّاب
// مفكوكة التشفير.
//
// هنا نقلب النموذج إلى «آمن افتراضاً»: كل ملف تحت Admin/ يمرّ عبر connect.php
// يتطلب دور admin أو super_admin، ما لم يكن في قائمة استثناء صريحة.
//
// نقاط تسجيل الدخول (Admin/auth/*, jwtService.php) لا تستدعي connect.php
// أصلاً، فلا تتأثر بهذه البوّابة ولا يمكن أن تُقفل على نفسها.
//
// ‏2026-08-07: وُسِّعت البوّابة لتشمل serviceapp/ أيضاً. كان 34 من 39 ملفاً
// ‏هناك بلا أي فحص دور — بينها getDriverByPhone و getPassengersByPhone و
// ‏update_complaint — أي أن أي حامل JWT صالح (راكب عادي) يقرأ بيانات
// ‏السائقين والركّاب ويغلق الشكاوى. تحققنا أن siro_rider و siro_driver لا
// ‏يستدعيان أي نقطة تحت serviceapp/، فالإغلاق لا يكسر تطبيقات الجوال.
//
// ⚠️ ‏لكل مجلد أدواره: تسجيل دخول تطبيق الخدمة (Admin/jwtService.php:51)
// ‏يصدر الدور 'service' لا 'admin'. فرضُ admin على serviceapp/ كان
// ‏سيمنع كل موظفي خدمة العملاء من كل نقاطهم.
$gatedDirs = array_filter([
realpath(__DIR__ . '/Admin') => ['admin', 'super_admin'],
realpath(__DIR__ . '/serviceapp') => ['service', 'admin', 'super_admin'],
], fn($k) => $k !== false, ARRAY_FILTER_USE_KEY);
$script = realpath($_SERVER['SCRIPT_FILENAME'] ?? '');
$gateRoles = null;
if ($script) {
foreach ($gatedDirs as $dir => $roles) {
if (str_starts_with($script, $dir . DIRECTORY_SEPARATOR)) {
$gateRoles = $roles;
break;
}
}
}
if ($gateRoles !== null) {
// نقاط تحت Admin/ تستدعيها تطبيقات الجوال بأدوار غير إدارية.
// تم التحقق من مواضع الاستدعاء الفعلية في siro_rider و siro_driver:
// errorApp.php → التطبيقان يبلّغان عن الأخطاء
// sendEmailToDrivertransaction.php → تطبيق السائق
// بقية روابط Admin/ المعرّفة في التطبيقين غير مستدعاة إطلاقاً.
$adminGateExempt = [
'errorApp.php',
'sendEmailToDrivertransaction.php',
];
if (!in_array(basename($script), $adminGateExempt, true)
&& !in_array($role, $gateRoles, true)
) {
securityLog('Admin gate blocked non-admin request', [
'script' => basename($script),
'role' => $role,
'user_id' => $user_id ?? 'unknown',
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
]);
http_response_code(403);
exit(json_encode([
'status' => 'failure',
'message' => 'Forbidden. Admin access required.',
], JSON_UNESCAPED_UNICODE));
}
}
// 3. Database Connection
try {
$con = Database::get('main');
} catch (Exception $e) {
http_response_code(500);
exit(json_encode(['error' => 'Database connection failed']));
}