Commit Graph
4 Commits
Author SHA1 Message Date
Hamza-AyedandClaude Opus 4.8 c258a8c4b8 fix: D4 — حدّ الطلبات كان مُعطَّلاً كلياً رغم أنه يبدو مفعَّلاً
ThrottlerModule.forRoot(...) كان مسجَّلاً في app.module.ts منذ البداية —
بلا أي حارس يطبّقه (لا APP_GUARD ولا @UseGuards). التسجيل وحده لا يفعل شيئاً
في NestJS: كل نقطة في الـAPI، بما فيها verify-otp و payouts/*، كانت بلا أي
حدّ طلبات إطلاقاً منذ اليوم الأول.

- APP_GUARD → ThrottlerGuard يُفعّل الحدّ العام (120/دقيقة) على كل نقطة
- عدّاد محاولات لكل (مستأجر، رقم) في AuthService.verifyOtp — الحماية
  الحقيقية ضد تخمين الرمز لا الحدّ العام: رمز 4 خانات = 10000 احتمال،
  ومهاجم يدوّر IP يتجاوز أي حدّ بالـIP وحده. 5 محاولات ثم إبطال الرمز،
  نفس نمط payouts.service (I4)
- حدود أضيق للأهداف عالية القيمة: send-otp (كل إرسال يكلّف رسالة واتساب
  مدفوعة فعلياً)، verify-otp، payouts/request، payouts/confirm
- HealthController مُستثنى (@SkipThrottle) — مراقبة تشغيل بلا بيانات حساسة

قرار وعي بالمخاطرة: بنيت أولاً حارساً مخصَّصاً يتتبّع بالمستخدم المصادَق
لا بالـIP وحده (مهم لموبايل — NAT عند مشغّلي الجوّال يجمع آلاف المستخدمين
خلف IP واحد)، لكن تطلّب حقناً يدوياً دقيقاً (InjectThrottlerOptions/
InjectThrottlerStorage) — خطأ فيه يمنع إقلاع التطبيق كاملاً، ولا بيئة هنا
لاختبار NestFactory.create() قبل الدفع (jest ينشئ الخدمات يدوياً فلا يكشف
أخطاء DI لحارس عالمي). حذفته ورجّحت الأمان بالتتبّع الافتراضي — موثّق في
docs/17 D4 لتُنفَّذ حين يمكن اختبارها فعلياً على السيرفر.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 17:47:03 +03:00
Hamza-AyedandClaude Opus 4.8 1eb79fee99 feat: المجموعة D — تطبيع الهاتف + ربط الجلسة بالجهاز
D1 — تطبيع أرقام الهاتف (JO/EG/SY):
- common/phone/phone.service.ts: مفتاح قانوني واحد لكل رقم حقيقي — يقبل
  صفراً محلياً/دولياً/+/00/بلا صفر ويرجع صيغة دولية موحّدة بلا +
- يعالج لبس مصر تحديداً الذي ذكره المالك: "01012345678" يُطبَّع بمفتاح 20
  الصحيح لا "2" — الخوارزمية عامة فلا تحتاج معرفة اللبس، فقط تحذف الصفر
  البادئ وتضيف مفتاح الدولة الحقيقي
- send-otp و verify-otp و platform/users/role تمرّ كلها بالتطبيع الآن؛
  كانت تخزّن/تبحث بالرقم الخام كما كُتب — رقم واحد بصيغتين = حسابان
- هجرة NormalizePhones تُصحّح حسابات الاختبار الموجودة على السيرفر، بحذر:
  تتخطّى أي تصادم بدل كسر القيد الفريد (tenant_id, phone)
- أُزيل config.callingCodes المكرّر — مصدر واحد للحقيقة

D2 — ربط الجلسة بالجهاز (نمط سيرو): **مبنيّ ومطفأ**
(AUTH_REQUIRE_DEVICE_BINDING=false) حتى يرسل فلاتر x-device-id. منفَّذ داخل
JwtStrategy.validate نفسها (passReqToCallback) لا كحارس يُضاف يدوياً لكل
متحكّم — فلا نقطة محميّة يمكن نسيانها. التوكن يحمل hash(deviceId) لا القيمة
الخام. verifyOtp/refresh يمرّران x-device-id من المتحكّم عند إصدار التوكن.

D3 — HMAC: منفَّذ فعلاً ضمن I6 (SigningService/SignatureGuard)، لا تكرار.

خطأ ضبطته قبل الدفع: كتبت مفتاح `auth:` ثانياً في configuration.ts —
كائنات JS تسمح بمفاتيح مكرّرة والأخير يطغى، فكان سيمحو otpDevMode/otpTtl/
otpLength بالكامل. دُمج في الكتلة الأصلية بدل مفتاح جديد.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 17:03:56 +03:00
Hamza-Ayed 4f11580d4a fix: ts compilation errors in auth 2026-07-16 16:05:28 +03:00
Hamza-Ayed 83f2d0854a Update codebase 2026-07-16 16:01:28 +03:00