Update: 2026-06-16 17:47:17

This commit is contained in:
Hamza-Ayed
2026-06-16 17:47:19 +03:00
parent 49899da6b2
commit b516fbc4ed
96 changed files with 6073 additions and 3187 deletions

514
IMPLEMENTATION_STEPS.md Normal file
View File

@@ -0,0 +1,514 @@
# إجراءات عملية - البدء الفوري بالإصلاحات
**تاريخ التحديث:** 16 يونيو 2026
**الأولوية:** 🔴 حرج جداً
---
## المرحلة 1⃣: الإجراءات الفورية (اليوم الأول - 4 ساعات)
### ✅ الخطوة 1: تعطيل نقاط نهاية المحفظة الخطيرة
**السبب:** منع الاحتيال المالي الفوري
```bash
# نسخ احتياطية أولاً
cp /walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php \
/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php.bak
cp /walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php \
/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php.bak
```
**التعطيل المؤقت:**
```php
<?php
// /walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php
// ⚠️ معطل مؤقتاً - يتم إصلاح الأمان
http_response_code(503);
echo json_encode([
'status' => 'error',
'message' => 'Wallet service temporarily disabled for security updates',
'eta' => '2026-06-17 00:00:00 UTC'
]);
exit;
?>
```
---
### ✅ الخطوة 2: إنشاء endpoint جديد في Backend
**الموقع:** `backend/wallet/add.php` (جديد)
```php
<?php
// backend/wallet/add.php - ✅ جديد وآمن
require_once __DIR__ . '/../core/bootstrap.php';
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://siromove.com');
header('Access-Control-Allow-Methods: POST');
try {
// 1⃣ مصادقة JWT إجبارية
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (!preg_match('/Bearer\s+(\S+)/', $authHeader, $matches)) {
http_response_code(401);
jsonError('Authentication required (JWT needed)', 401);
}
// التحقق من JWT
$jwtService = new JwtService($redis);
try {
$decoded = $jwtService->verifyAccessToken($matches[1]);
} catch (Exception $e) {
http_response_code(401);
jsonError('Invalid or expired token', 401);
}
// 2⃣ التحقق من الدور (التفويض)
if ($decoded->role !== 'driver') {
http_response_code(403);
jsonError('Only drivers can add funds', 403);
}
$driverID = (int) $decoded->id;
$amount = (float) filterRequest('amount');
$source = filterRequest('source');
// 3⃣ تحديد السرعة
$limiter = new RateLimiter($redis);
try {
$limiter->enforce("wallet_add_" . $driverID, 'add');
} catch (Exception $e) {
http_response_code(429);
jsonError('Too many requests. Please try again later.', 429);
}
// 4⃣ التحقق من المبلغ
if ($amount <= 0) {
jsonError('Amount must be greater than 0', 400);
}
if ($amount > 10000) {
jsonError('Amount cannot exceed 10,000', 400);
}
// 5⃣ تسجيل التدقيق
securityLog("Driver wallet add request", [
'driver_id' => $driverID,
'amount' => $amount,
'source' => $source,
'timestamp' => date('Y-m-d H:i:s')
]);
// 6⃣ حفظ في قاعدة البيانات المحلية أولاً
$con = Database::get('main');
$stmt = $con->prepare(
"INSERT INTO driver_wallet_requests (driver_id, amount, source, status)
VALUES (?, ?, ?, 'pending')"
);
$stmt->execute([$driverID, $amount, $source]);
$requestID = $con->lastInsertId();
// 7⃣ استدعاء خادم المحفظة عبر S2S API
$walletConnector = new WalletConnector();
try {
$response = $walletConnector->call('ride/driverWallet/add_s2s', [
'driver_id' => $driverID,
'amount' => $amount,
'source' => $source,
'request_id' => $requestID,
'backend_id' => getenv('BACKEND_ID'),
]);
// ✅ النجاح
$stmt = $con->prepare(
"UPDATE driver_wallet_requests SET status = 'completed' WHERE id = ?"
);
$stmt->execute([$requestID]);
jsonSuccess(['message' => 'Funds added successfully']);
} catch (Exception $e) {
// فشل العملية - سجل الخطأ
$stmt = $con->prepare(
"UPDATE driver_wallet_requests SET status = 'failed', error = ? WHERE id = ?"
);
$stmt->execute([$e->getMessage(), $requestID]);
securityLog("Wallet S2S call failed", [
'driver_id' => $driverID,
'error' => $e->getMessage()
]);
http_response_code(500);
jsonError('Failed to process payment', 500);
}
} catch (Exception $e) {
securityLog("Wallet endpoint error: " . $e->getMessage());
http_response_code(500);
jsonError('Internal server error', 500);
}
?>
```
---
### ✅ الخطوة 3: إنشاء فئة WalletConnector آمنة
**الموقع:** `backend/core/WalletConnector.php` (جديد)
```php
<?php
// backend/core/WalletConnector.php - ✅ جديد وآمن
class WalletConnector {
private $walletUrl;
private $hmacSecret;
private $backendID;
private $timeout = 10;
public function __construct() {
$this->walletUrl = getenv('WALLET_API_URL') ?? 'https://walletintaleq.intaleq.xyz/v2/main/';
$this->hmacSecret = getenv('WALLET_HMAC_SECRET');
$this->backendID = getenv('BACKEND_ID');
if (!$this->walletUrl || !$this->hmacSecret || !$this->backendID) {
throw new Exception("Missing wallet configuration");
}
}
/**
* استدعاء API خادم المحفظة بأمان (S2S)
*/
public function call($endpoint, $data) {
// ✅ أضف timestamp ونonce لمنع Replay Attacks
$data['timestamp'] = time();
$data['nonce'] = bin2hex(random_bytes(16));
$data['backend_id'] = $this->backendID;
// ✅ فرز البيانات
ksort($data);
// ✅ إنشاء JSON payload
$payload = json_encode($data);
// ✅ إنشاء توقيع HMAC
$signature = hash_hmac('sha256', $payload, $this->hmacSecret);
// ✅ إرسال الطلب
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->walletUrl . $endpoint,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
// ✅ رؤوس HTTP آمنة
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Signature: ' . $signature,
'X-Timestamp: ' . $data['timestamp'],
'X-Backend-ID: ' . $this->backendID,
'User-Agent: SiroBackend/1.0',
],
// ✅ تأمين SSL/TLS
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => '/etc/ssl/certs/ca-bundle.crt',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// ✅ فحص الأخطاء
if ($curlError) {
throw new Exception("CURL Error: $curlError");
}
// ✅ فحص رمز HTTP
if ($httpCode !== 200) {
throw new Exception("Wallet API returned HTTP $httpCode: $response");
}
// ✅ فحص الاستجابة
$decoded = json_decode($response, true);
if ($decoded === null) {
throw new Exception("Invalid JSON response from wallet");
}
if ($decoded['status'] !== 'success') {
throw new Exception("Wallet error: " . ($decoded['message'] ?? 'Unknown'));
}
return $decoded;
}
}
?>
```
---
### ✅ الخطوة 4: تعديل طريقة الترحيل
**قاعدة البيانات الجديدة:**
```sql
-- جديد: جدول لتتبع طلبات إضافة الأموال
CREATE TABLE driver_wallet_requests (
id INT AUTO_INCREMENT PRIMARY KEY,
driver_id INT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
source VARCHAR(50),
status ENUM('pending', 'completed', 'failed') DEFAULT 'pending',
error TEXT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (driver_id) REFERENCES driver(id),
INDEX (driver_id, status),
INDEX (created_at)
);
-- ملف .env جديد (اضف هذه المتغيرات)
# wallet configuration
WALLET_API_URL=https://walletintaleq.intaleq.xyz/v2/main/
WALLET_HMAC_SECRET=<secret-key-here-change-me>
BACKEND_ID=siromove-backend-01
```
---
## المرحلة 2⃣: إصلاح التشفير (اليوم الثاني - 4 ساعات)
### ✅ الخطوة 5: تعديل encrypt_decrypt.php
**الملف:** `backend/encrypt_decrypt.php`
سأنشئ نسخة محدثة آمنة:
```php
<?php
// backend/encrypt_decrypt.php - ✅ تم تحديثه
class EncryptionHelper {
private $key;
public function __construct($key = null) {
if ($key === null) {
$key = getenv('ENC_KEY');
if (!$key) {
$keyPath = getenv('ENCRYPTION_KEY_PATH');
if ($keyPath && file_exists($keyPath)) {
$key = trim(file_get_contents($keyPath));
}
}
}
if (strlen($key) !== 32) {
throw new Exception("Key must be exactly 32 bytes (256 bits) for AES-256");
}
$this->key = $key;
}
// ✅ ضمّ IV مع النص المشفر قبل base64_encode
private function addPadding($data, $blockSize = 16) {
$pad = $blockSize - (strlen($data) % $blockSize);
return $data . str_repeat(chr($pad), $pad);
}
private function removePadding($data) {
$pad = ord($data[strlen($data) - 1]);
if ($pad < 1 || $pad > 16) {
throw new Exception("Invalid padding");
}
return substr($data, 0, -$pad);
}
/**
* تشفير البيانات بـ IV عشوائي
* ✅ التحسين: IV عشوائي لكل تشفير
*/
public function encryptData($plainText) {
try {
$plainText = mb_convert_encoding($plainText, 'UTF-8');
$paddedText = $this->addPadding($plainText);
// ✅ توليد IV عشوائي - هذا هو الإصلاح الحرج
$randomIV = openssl_random_pseudo_bytes(16, $strongRandom);
if (!$strongRandom) {
throw new Exception("openssl_random_pseudo_bytes failed to generate strong random");
}
// تشفير البيانات
$encrypted = openssl_encrypt(
$paddedText,
'AES-256-CBC',
$this->key,
OPENSSL_RAW_DATA,
$randomIV
);
if (!$encrypted) {
throw new Exception("Encryption failed");
}
// ✅ ضمّ IV مع النص المشفر (IV يجب أن يكون أول 16 بايت)
$encryptedWithIV = $randomIV . $encrypted;
// تحويل إلى base64
return base64_encode($encryptedWithIV);
} catch (Exception $e) {
error_log("Encryption error: " . $e->getMessage());
throw $e;
}
}
/**
* فك التشفير - استخرج IV من البيانات المشفرة
* ✅ التحسين: قراءة IV من البيانات المشفرة
*/
public function decryptData($encryptedData) {
try {
// فك base64
$encrypted = base64_decode($encryptedData, true);
if (!$encrypted) {
throw new Exception("Invalid base64 data");
}
if (strlen($encrypted) < 16) {
throw new Exception("Encrypted data too short");
}
// ✅ استخرج IV من أول 16 بايت
$iv = substr($encrypted, 0, 16);
$ciphertext = substr($encrypted, 16);
// فك التشفير
$decrypted = openssl_decrypt(
$ciphertext,
'AES-256-CBC',
$this->key,
OPENSSL_RAW_DATA,
$iv
);
if (!$decrypted) {
throw new Exception("Decryption failed");
}
// إزالة الـ padding
$unpadded = $this->removePadding($decrypted);
return $unpadded;
} catch (Exception $e) {
error_log("Decryption error: " . $e->getMessage());
throw $e;
}
}
}
// استخدام
$encryption = new EncryptionHelper();
// ✅ التشفير
$plaintext = "+20123456789";
$encrypted1 = $encryption->encryptData($plaintext);
$encrypted2 = $encryption->encryptData($plaintext);
echo "Encryption 1: $encrypted1\n";
echo "Encryption 2: $encrypted2\n";
echo "Different? " . ($encrypted1 !== $encrypted2 ? "YES ✅" : "NO ❌") . "\n";
// ✅ فك التشفير
$decrypted = $encryption->decryptData($encrypted1);
echo "Decrypted: $decrypted\n";
echo "Correct? " . ($decrypted === $plaintext ? "YES ✅" : "NO ❌") . "\n";
?>
```
---
## المرحلة 3⃣: تقليل الأذونات (ساعة واحدة)
### ✅ الخطوة 6: تحديث AndroidManifest.xml
```xml
<!-- قبل -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- بعد: احذف هذه الأسطر الأربعة ↑ -->
```
**السبب:**
- ❌ لا يوجد استخدام فعلي لـ External Storage
- ❌ لا يوجد استخدام لـ SYSTEM_ALERT_WINDOW
- ⚠️ MODIFY_AUDIO_SETTINGS يمكن استبداله بـ requestAudioFocus
---
## المرحلة 4⃣: تحديث الروابط (30 دقيقة)
### ✅ الخطوة 7: تحديث functions.php
في `backend/functions.php`:
```php
// ❌ احذف هذه:
function getAllowedSocketUrls(): array {
return [
'http://188.68.36.205:2021',
'http://188.68.36.205:3031',
'https://location.intaleq.xyz',
];
}
// ✅ استبدل بهذا:
function getAllowedSocketUrls(): array {
$urls = getenv('ALLOWED_SOCKET_URLS');
if ($urls) {
return array_map('trim', explode(',', $urls));
}
return [
'https://location.siromove.com', // HTTPS فقط
'https://socket.siromove.com', // HTTPS فقط
];
}
```
**في .env:**
```
# Socket URLs - HTTPS only
ALLOWED_SOCKET_URLS=https://location.siromove.com,https://socket.siromove.com
```
---
## ✅ الخلاصة والجدول الزمني
| المرحلة | الخطوات | المدة | التاريخ المتوقع |
| ------------ | ------------------------------------------ | ------------- | --------------- |
| 1 | تعطيل + Backend endpoint + WalletConnector | 4 س | اليوم (16/6) |
| 2 | تحديث encrypt_decrypt.php + اختبار | 4 س | غد (17/6) |
| 3 | تقليل الأذونات + نشر تطبيق | 1 س | غد (17/6) |
| 4 | تحديث الروابط + اختبار | 30 د | غد (17/6) |
| **الإجمالي** | - | **~9.5 ساعة** | **بحلول 17/6** |