authenticate(); error_log("[Wallet_SSO] Authenticated Admin ID: " . ($admin->user_id ?? 'N/A') . " | Role: " . ($admin->role ?? 'N/A')); if ($admin->role !== 'admin' && $admin->role !== 'super_admin') { jsonError("Unauthorized. Admin access required."); exit; } try { // جلب المفتاح المشترك لسيرفر المحفظة من متغير البيئة أو الملف $payKeyPath = getenv('SECRET_KEY_PAY_PATH'); $payKey = ($payKeyPath && file_exists($payKeyPath)) ? trim(file_get_contents($payKeyPath)) : getenv('SECRET_KEY_PAY'); if (empty($payKey)) { $fallbackPath = getenv('SECRET_KEY_PATH'); $payKey = ($fallbackPath && file_exists($fallbackPath)) ? trim(file_get_contents($fallbackPath)) : null; } if (empty($payKey)) { jsonError("Internal configuration error: Shared secret key missing."); exit; } $issuer = 'Tripz-Wallet'; $audience = 'Tripz-Wallet'; $hmacSecret = getenv('SECRET_KEY_HMAC') ?: ''; $ttl = 600; // 10 دقائق $iat = time(); $exp = $iat + $ttl; $jti = bin2hex(random_bytes(16)); // محتوى التوكن (Payload) $payload = [ 'iss' => $issuer, 'aud' => $audience, 'user_id' => $admin->user_id, 'role' => 'admin', // نرسل 'admin' للمحفظة لضمان التوافق مع برمجياتها القديمة 'iat' => $iat, 'exp' => $exp, 'jti' => $jti ]; // إلغاء التوكن القديم إذا وجد في Redis if ($redis) { $oldJtiKey = "wallet_jti:" . $admin->user_id; $oldJti = $redis->get($oldJtiKey); if ($oldJti) { // إضافة التوكن القديم للقائمة السوداء $redis->setex("jwt:blacklist:$oldJti", $ttl + 60, '1'); } // تخزين الـ JTI الجديد $redis->setex($oldJtiKey, $ttl, $jti); } // إضافة بصمة الجهاز للتوكن لزيادة الأمان $fpHeader = $_SERVER['HTTP_X_DEVICE_FP'] ?? null; $fpPepper = getenv('FP_PEPPER'); if ($fpHeader && $fpPepper) { $payload['fingerPrint'] = hash('sha256', $fpHeader . $fpPepper); } // توليد التوكن $jwt = JWT::encode($payload, $payKey, 'HS256'); // حساب الـ HMAC Hash المطلوب لسيرفر المحفظة $hmacHash = hash_hmac('sha256', (string)$admin->user_id, $hmacSecret); printSuccess([ "status" => "success", "jwt" => $jwt, "hmac" => $hmacHash, "expires_in" => $ttl ]); } catch (Exception $e) { error_log("[Admin Wallet SSO Error] " . $e->getMessage()); jsonError("An internal error occurred. Please try again later."); }