cleanup: trim bloated multi-line comments across the project

This commit is contained in:
2026-08-26 03:22:20 +03:30
parent 83435c5a5f
commit 683bd40169
27 changed files with 235 additions and 699 deletions

View File

@@ -116,24 +116,10 @@ class RequestOTPView(APIView):
serializer.is_valid(raise_exception=True)
phone = serializer.validated_data['phone']
# حداقل فاصله‌ی زمانی بین دو درخواست برای همون شماره (burst
# protection). سقفِ ساعتیِ زیر جلویِ حجمِ کلی رو می‌گیره، اما به‌تنهایی
# جلویِ این رو نمی‌گیره که همون ۵ تلاشِ مجاز در عرضِ چند ثانیه/کمتر
# از یک ثانیه مصرف بشن (که هم به‌معنایِ flood پیامکی روی یک شماره‌ی
# مشخصه، هم می‌تونه با invalidate کردنِ پی‌درپیِ OTPهای قبلی
# (رفتارِ «فقط آخرین کد معتبره» که پایین‌تره) عملاً یک DoS روی
# کاربرِ واقعیِ اون شماره باشه). چک این cooldown *قبل* از شمارنده‌ی
# ساعتی انجام می‌شه تا یک درخواستِ بلاک‌شده توسطِ cooldown سهمیه‌ی
# ساعتی رو مصرف نکنه. از همون الگویِ اتمیکِ cache.add استفاده شده
# (دقیقاً همون مکانیزمِ زیر و مکانیزمِ LoginView).
#
# کلید cooldown به‌جای یک فلگِ ساده، زمانِ epoch انقضاء رو ذخیره
# می‌کنه؛ این‌طوری وقتی add شکست بخوره (کلید از قبل هست)، بدونِ
# هیچ خواندنِ ناامنی می‌شه دقیقاً محاسبه کرد چند ثانیه تا پایانِ
# cooldown مونده و اون رو هم در بدنه‌ی پاسخ (retryAfter) و هم در
# هدرِ استانداردِ Retry-After برگردوند — این‌طوری frontend
# countdown رو دقیقاً از رویِ همین پاسخِ backend شروع می‌کنه، نه
# از رویِ یک عددِ hardcode‌شده‌ی سمتِ کلاینت که مرجعِ امنیتی نیست.
# حداقل فاصله‌ی زمانی بین دو درخواستِ همون شماره (burst protection)؛
# قبل از شمارنده‌ی ساعتی چک می‌شه تا یک درخواستِ بلاک‌شده سهمیه‌ی
# ساعتی رو مصرف نکنه. کلید مقدارِ epoch انقضا رو ذخیره می‌کنه تا
# retryAfter/هدرِ Retry-After بدونِ خواندنِ اضافه محاسبه بشه.
phone_cooldown_key = f'otp_request_phone_cooldown:{phone}'
cooldown_seconds = settings.OTP_REQUEST_PHONE_COOLDOWN_SECONDS
now_epoch = timezone.now().timestamp()
@@ -161,13 +147,9 @@ class RequestOTPView(APIView):
headers={'Retry-After': str(retry_after)},
)
# محدودیت صدور OTP بر اساس شماره تلفن، مستقل از throttle IP-محورِ
# otp_request بالا. throttle IP-محور به‌تنهایی کافی نیست چون یک
# مهاجم می‌تونه درخواست‌های تکراری برای یک شماره رو بین چند IP
# مختلف پخش کنه و پیامک OTP رو flood کنه. الگوی cache.add/incr
# همون الگوی atomic زیرِ LoginView است: cache.add فقط وقتی کلید
# وجود نداره مقدار می‌ذاره (اتمیک روی سطح backend cache)، پس دو
# درخواستِ هم‌زمان نمی‌تونن هر دو از یک non-atomic check رد بشن.
# محدودیتِ صدورِ OTP بر اساسِ شماره، مستقل از throttleِ IP-محورِ بالا
# (وگرنه یه مهاجم می‌تونه بینِ چند IP پخش کنه). cache.add فقط وقتی
# کلید نیست مقدار می‌ذاره، پس اتمیکه.
phone_requests_key = f'otp_request_phone_attempts:{phone}'
if cache.add(phone_requests_key, 1, timeout=settings.OTP_REQUEST_PHONE_WINDOW_SECONDS):
attempt_count = 1
@@ -202,13 +184,9 @@ class RequestOTPView(APIView):
try:
send_otp_sms(phone=phone, code=code)
except OTPDeliveryError:
# ⚠️ فیکس: کاربر عملاً کد رو دریافت نکرده (ارسالِ پیامک شکست
# خورده)، پس cooldownِ ۱۲۰ثانیه‌ای که بالاتر برای همین درخواست
# ثبت شده نباید جلوی تلاشِ فوریِ بعدیِ کاربر رو بگیره؛ در غیرِ
# این‌صورت کاربر ۲ دقیقه معطل می‌مونه بدونِ اینکه اصلاً کدی
# گرفته باشه. سقفِ ساعتیِ per-phone (بالاتر) و throttle
# IP-محور دست‌نخورده می‌مونن — این‌ها محدودیتِ حجمِ کلی‌ان، نه
# cooldownِ بینِ-درخواستی، و منطقِ متفاوتی دارن.
# ارسال شکست خورده یعنی کاربر کدی نگرفته؛ cooldown رو پاک می‌کنیم
# تا مجبور نشه ۲ دقیقه بدونِ داشتنِ کد منتظر بمونه. سقفِ ساعتی/
# throttleِ IP دست‌نخورده می‌مونن (محدودیتِ حجم، نه این cooldown).
cache.delete(phone_cooldown_key)
raise