109 lines
4.9 KiB
PHP
109 lines
4.9 KiB
PHP
<?php
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ride/call/turn_credentials.php
|
|
// الغرض : بيانات اعتماد مؤقتة لخادم TURN (coturn use-auth-secret)
|
|
// التطبيق: السائق والراكب معاً — نفس القناة تخدم مكالمات الرحلات
|
|
// ومكالمات توصيل الطعام المقنّعة.
|
|
// المصادقة: JWT (driver أو passenger)
|
|
// ───────────────────────────────────────────────────────────────
|
|
// لماذا بيانات مؤقتة ولا مستخدم ثابت: كلمة مرور TURN ثابتة داخل تطبيق
|
|
// منشور = مفتاح تمرير مجاني للجميع بمجرد فكّ حزمة APK. آلية coturn
|
|
// القياسية: username = "{انتهاء الصلاحية}:{المستخدم}"، والكلمة
|
|
// = base64(HMAC-SHA1(secret, username)). الخادم يتحقق حسابياً بلا
|
|
// قاعدة بيانات ولا مزامنة، والصلاحية تنتهي تلقائياً.
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../../core/bootstrap.php';
|
|
require_once __DIR__ . '/../../functions.php';
|
|
|
|
$limiter = new RateLimiter($redis);
|
|
$limiter->enforce(RateLimiter::identifier(), 'api');
|
|
|
|
$jwtService = new JwtService($redis);
|
|
$decoded = $jwtService->authenticate();
|
|
|
|
$role = (string)($decoded->role ?? '');
|
|
$userId = (string)($decoded->user_id ?? '');
|
|
if (!in_array($role, ['driver', 'passenger'], true) || $userId === '') {
|
|
jsonError('Forbidden — driver or passenger token required', 403);
|
|
}
|
|
|
|
// السر نفسه المُمرَّر إلى coturn — من /keys أولاً كبقية أسرار المشروع
|
|
$secret = '';
|
|
$secretPath = getenv('TURN_SECRET_PATH') ?: '/keys/turn_secret';
|
|
if (is_readable($secretPath)) {
|
|
$secret = trim((string)file_get_contents($secretPath));
|
|
}
|
|
if ($secret === '') {
|
|
$secret = (string)(getenv('TURN_STATIC_AUTH_SECRET') ?: '');
|
|
}
|
|
|
|
$turnHost = getenv('TURN_HOST') ?: '';
|
|
|
|
// بلا إعداد TURN لا نُفشل المكالمة: نُعيد STUN فقط ويبقى السلوك كما كان
|
|
// قبل إضافة TURN (اتصال مباشر ينجح في أغلب الشبكات المنزلية والـ WiFi).
|
|
if ($secret === '' || $turnHost === '') {
|
|
appLog('[TURN] not configured (missing secret or TURN_HOST) — returning STUN only', 'WARNING');
|
|
jsonSuccess([
|
|
'ice_servers' => turnDefaultStunServers(),
|
|
'ttl' => 0,
|
|
'turn_enabled' => false,
|
|
]);
|
|
}
|
|
|
|
$ttl = (int)(getenv('TURN_CREDENTIAL_TTL') ?: 43200); // 12 ساعة
|
|
$expiry = time() + $ttl;
|
|
$username = $expiry . ':' . $role . '_' . $userId;
|
|
$password = base64_encode(hash_hmac('sha1', $username, $secret, true));
|
|
|
|
$turnPort = (int)(getenv('TURN_PORT') ?: 3478);
|
|
$turnTlsPort = (int)(getenv('TURN_TLS_PORT') ?: 5349);
|
|
|
|
// الترتيب مقصود: STUN أولاً (اتصال مباشر أرخص وأقل تأخيراً)، ثم UDP TURN،
|
|
// ثم TCP/TLS على 5349 للشبكات التي تحجب UDP كلياً (بعض شبكات الشركات).
|
|
$iceServers = turnDefaultStunServers();
|
|
$iceServers[] = [
|
|
'urls' => "turn:{$turnHost}:{$turnPort}?transport=udp",
|
|
'username' => $username,
|
|
'credential' => $password,
|
|
];
|
|
$iceServers[] = [
|
|
'urls' => "turn:{$turnHost}:{$turnPort}?transport=tcp",
|
|
'username' => $username,
|
|
'credential' => $password,
|
|
];
|
|
// turns: يُعلَن فقط إذا كانت شهادة TLS مركّبة فعلاً على coturn — وإلا صار
|
|
// مساراً ميتاً في قائمة ICE يُبطئ التفاوض بلا أن يعمل أبداً.
|
|
if (getenv('TURN_TLS_ENABLED') === 'true') {
|
|
$iceServers[] = [
|
|
'urls' => "turns:{$turnHost}:{$turnTlsPort}?transport=tcp",
|
|
'username' => $username,
|
|
'credential' => $password,
|
|
];
|
|
}
|
|
|
|
jsonSuccess([
|
|
'ice_servers' => $iceServers,
|
|
'ttl' => $ttl,
|
|
'expires_at' => $expiry,
|
|
'turn_enabled' => true,
|
|
]);
|
|
|
|
function turnDefaultStunServers(): array
|
|
{
|
|
$host = getenv('TURN_HOST') ?: '';
|
|
$port = (int)(getenv('TURN_PORT') ?: 3478);
|
|
|
|
// خادمنا يعمل STUN أيضاً — نضعه أولاً، ونُبقي خوادم Google احتياطاً
|
|
// إن سقط خادمنا (اكتشاف العنوان العام فقط، لا يمرّ عبره أي صوت).
|
|
$servers = [];
|
|
if ($host !== '') {
|
|
$servers[] = ['urls' => "stun:{$host}:{$port}"];
|
|
}
|
|
$servers[] = ['urls' => 'stun:stun.l.google.com:19302'];
|
|
$servers[] = ['urls' => 'stun:stun1.l.google.com:19302'];
|
|
return $servers;
|
|
}
|