Food delivery driver module + masked calls + TURN
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<?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;
|
||||
}
|
||||
Reference in New Issue
Block a user