feat: المجموعة E (كشف الاحتيال) + تشفير الهاتف at-rest
E — اتصال ثم إلغاء (من driver_ride_scam عند سيرو): - E1: driver_called_passenger + last_call_at/by/count على الرحلة نفسها لا Redis فقط — حقيقة دائمة تفيد التحقيق بعد انتهاء الرحلة وزوالها من الكاش. يُسجَّل عند call:offer (بدء المكالمة الفعلي) في RealtimeGateway عبر Repository<Trip> مباشرة — لا استيراد TripsModule كاملاً (يستورد RealtimeModule أصلاً، فدورة استيراد) - E2: FraudService.recordCallThenCancel — عدّاد يومي منفصل عن عدّاد الإلغاء العام بالساعة. 3/يوم = إنذار لا يمنع الإلغاء، 6/يوم = حظر مؤقت (طلب المالك حرفياً). يرتبط فقط إن كانت المكالمة خلال 30 دقيقة من الإلغاء تشفير الهاتف at-rest (ملاحظة المالك) — بفهرس أعمى منفصل، لا تشفير ساذج: - AES-256-GCM عشوائي IV يمنع WHERE phone = :x من المطابقة أصلاً (كل تشفير مختلف شكلاً حتى لنفس الرقم) — لو طُبِّق التشفير مباشرة بلا هذا لكسر تسجيل الدخول بالكامل بصمت - users.phone_bidx = HMAC-SHA256(الرقم المطبَّع) — حتمي، يصلح للبحث وللقيد الفريد. القيد انتقل من (tenant_id, phone) إلى (tenant_id, phone_bidx) — القديم كان سيقبل تكرار نفس الرقم الحقيقي فعلياً - findByPhone/create يحسبان البصمة؛ لا نقطة أخرى تقرأ phone بمساواة خام - هجرة EncryptPhone تُشفّر الصفوف القائمة فوراً وتبني البصمة بأثر رجعي — استثناء متعمَّد من تسامح decrypt() المعتاد (الهاتف عمود بحث يومي، خطره كنص صافٍ أعلى من name) - يعتمد على تطبيع D1: بصمة حتمية لنفس *النص*، فلا بد أن يصل الرقم مطبَّعاً قبلها وإلا عاد نفس الرقم بصيغتين ليصير رقمين مرة أخرى هجرات: TripCallSignal · EncryptPhone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
1eb79fee99
commit
253fbb4b2a
+10
-6
@@ -17,15 +17,19 @@ name: string;
|
||||
```
|
||||
|
||||
## المطبّق حالياً
|
||||
- `users.name` · `drivers.vehicle_plate`.
|
||||
- `users.name` · `users.phone` · `drivers.vehicle_plate`.
|
||||
|
||||
## الحقول القابلة للبحث (مثل الهاتف) — الحل الصحيح
|
||||
تشفير GCM عشوائي **يمنع المطابقة بالتساوي** (كل تشفير مختلف). للبحث نستخدم **فهرس أعمى (blind index)**: عمود إضافي = `HMAC-SHA256(القيمة)` حتمي للبحث + العمود المشفّر للتخزين. مخطّط عند بناء بحث الهاتف/الهوية.
|
||||
## الحقول القابلة للبحث (مثل الهاتف) — ✅ منفَّذ (docs/17 — D1 إضافة)
|
||||
تشفير GCM عشوائي **يمنع المطابقة بالتساوي** (كل تشفير مختلف) — `WHERE phone = :x` لا يطابق أبداً حتى مع نفس الرقم. الحل: **فهرس أعمى (blind index)** — `users.phone_bidx = HMAC-SHA256(canonicalPhone)` حتمي، عمود إضافي غير مشفَّر (بصمة أحادية الاتجاه، لا تكشف الرقم). كل بحث وتفرّد على الهاتف يمرّ عبره لا عبر `phone`:
|
||||
- `UsersService.findByPhone` يحسب `blindIndex(phone)` ويبحث به.
|
||||
- القيد الفريد `(tenant_id, phone_bidx)` — لا `(tenant_id, phone)` (ذاك كان سيقبل تكرار نفس الرقم الحقيقي لأن كل تشفير مختلف شكلاً).
|
||||
- **يعتمد على تطبيع D1**: البصمة حتمية لنفس *النص*، فلا بد أن يصل `phone` مطبَّعاً (`common/phone/phone.service.ts`) قبل الوصول لهذا الكود — وإلا اعتُبر نفس الرقم بصيغتين مختلفتين رقمين مختلفين مرة أخرى.
|
||||
|
||||
## الميغريشن (صحيح ومتوافق)
|
||||
- **لا تغيير مخطّط:** الأعمدة `varchar` تتّسع للنص المشفّر (base64). لا هجرة لازمة لتحويل النوع.
|
||||
- **تسامح انتقالي:** `decrypt` يُرجع النص القديم غير المشفّر كما هو (يبدأ بلا `v1:`) — فلا تنكسر القراءة على بيانات قديمة؛ والكتابة الجديدة تُشفّر.
|
||||
- **عند نقل بيانات حقيقية من سيرو:** تُقرأ مفكوكةً من سيرو ثم تُكتب فتُشفَّر عندنا تلقائياً.
|
||||
- **لا تغيير مخطّط لـ`varchar`:** الأعمدة تتّسع للنص المشفّر (base64). لا هجرة لتحويل النوع.
|
||||
- **تسامح انتقالي:** `decrypt` يُرجع النص القديم غير المشفّر كما هو (يبدأ بلا `v1:`) — فلا تنكسر القراءة على بيانات قديمة.
|
||||
- **الهاتف استثناء متعمَّد لهذا التسامح**: هجرة `EncryptPhone` تُشفّر الصفوف القائمة **فوراً** (لا تتركها صافية للأبد بالاعتماد على `decrypt` المتسامح) — لأن `phone` عمود بحث نشط يومياً (كل تسجيل دخول)، ونصّه الصافي في القاعدة أخطر من `name` (نادراً ما يُقرأ مباشرة كنص خام). نفس الهجرة تبني `phone_bidx` بأثر رجعي لكل صف قائم.
|
||||
- **عند نقل بيانات حقيقية من سيرو:** تُقرأ مفكوكةً من سيرو ثم تُكتب فتُشفَّر عندنا تلقائياً — ويجب تمريرها عبر `PhoneService.normalize` أولاً قبل الكتابة، وإلا فسدت البصمة.
|
||||
|
||||
## ما يُشفَّر مستقبلاً
|
||||
وثائق السائق وأرقام الهوية/الرخصة (وحدة الوثائق)، ووجهات السحب الحساسة، وأي PII يُضاف — بنفس المحوّل.
|
||||
|
||||
Reference in New Issue
Block a user