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

@@ -23,25 +23,10 @@ from .services import apply_order_payment_result, create_order
class GuestAwareBazaarThrottle(ScopedRateThrottle):
"""
⚠️ اضافه شده: همون مشکلِ GuestAwareAIThrottle (ai_tutor/views.py)،
GuestAwareFamilyThrottle (family/views.py) و GuestAwareDiscountThrottle/
GuestAwarePurchaseThrottle (discount/views.py، subscription/views.py)
اینجا هم هست. ScopedRateThrottle استاندارد برای درخواستِ احرازهویت‌شده
از request.user.pk به‌عنوانِ کلیدِ throttle استفاده می‌کنه؛ چون
GuestSessionView با هر deviceId جدید یک کاربرِ مهمانِ تازه (pk جدید)
می‌سازه، یک مهاجم می‌تونست با ساختنِ پی‌درپیِ حساب‌های مهمان، برای هر
حساب یک bucket تازه از throttle_scope 'bazaar_verify' بگیره — درحالی‌که
هر درخواستِ پذیرفته‌شده یک فراخوانیِ سرور-به-سرور به API بازار رو
تریگر می‌کنه.
دقیقاً طبقِ همون الگو: فقط برای کاربرهای مهمان (is_guest=True) کلیدِ
cache از pk کاربر به IP کلاینت (get_ident) تغییر می‌کنه، پس همه‌ی
حساب‌های مهمانِ ساخته‌شده از یک IP یک bucket مشترک دارن و چرخشِ حساب
دیگه bucket تازه نمی‌ده. رفتارِ throttle برای کاربرهای غیرمهمان
(ثبت‌نام‌شده) دقیقاً مثلِ قبل (کلید بر اساسِ pk) باقی می‌مونه؛ منطقِ
verify/order ownership/transaction/apply-payment دست‌نخورده‌ست.
"""
"""همون الگوی GuestAwareAIThrottle/GuestAwareFamilyThrottle/etc: چرخشِ
حساب مهمان (هر deviceId یه pk تازه) نباید bucket تازه‌ی bazaar_verify
بده، چون هر درخواستِ پذیرفته‌شده یه فراخوانیِ سرور-به-سرور به بازاره.
برای مهمان‌ها کلیدِ cache بر اساسِ IP هست، نه pk."""
def get_cache_key(self, request, view):
user = request.user
@@ -121,14 +106,10 @@ class PaymentWebhookView(APIView):
"""
permission_classes = [HasWebhookSecret]
# ⚠️ اضافه شده: این endpoint قبلاً هیچ throttleای نداشت، درحالی‌که فقط
# با مقایسه‌ی یک هدرِ ثابت (X-Webhook-Secret) محافظت می‌شه؛ بدونِ
# throttle، تعدادِ نامحدودی تلاش برای حدسِ این سکرت (یا fuzz کردنِ
# orderId بعد از افشای احتمالیِ سکرت) ممکن بود، درحالی‌که یک حدسِ
# درست باعثِ paid شدنِ واقعیِ سفارش و فعال‌سازیِ اشتراک می‌شه. چون
# این caller یک کاربرِ اپ نیست (خودِ درگاهِ پرداخته)، از یک
# ScopedRateThrottleِ سادهٔ IP-محور استفاده شده، نه الگویِ
# GuestAware*Throttle (که نیازمندِ request.user است).
# این endpoint فقط با مقایسه‌ی هدرِ ثابتِ X-Webhook-Secret محافظت می‌شه،
# پس throttle لازمه تا حدسِ سکرت (یا fuzzِ orderId) محدود بمونه. چون
# caller خودِ درگاهه نه یک کاربرِ اپ، از ScopedRateThrottleِ IP-محور
# استفاده شده، نه الگویِ GuestAware*Throttle که نیازمندِ request.user است.
throttle_scope = 'payment_webhook'
throttle_classes = [ScopedRateThrottle]
@@ -182,19 +163,11 @@ class BazaarVerifyPurchaseView(APIView):
"""
permission_classes = [IsAuthenticated]
# ⚠️ افزوده شده: این endpoint یک فراخوانیِ سرور-به-سرور به API بازار
# (verify_purchase) رو تریگر می‌کنه؛ بدون throttle مخصوص، یک کاربر
# می‌تونست با ارسال مکرر purchaseToken نامعتبر، بار زیادی روی سرویس
# بازار و بک‌اند بندازه. throttle_scope مجزا (bazaar_verify) جدا از
# نرخ‌های دیگه (مثل otp_*) تنظیم شده.
# ⚠️ اصلاح شده: چون کاربرهای مهمان (GuestSessionView) با هر deviceId
# جدید یک pk تازه می‌گیرن، ScopedRateThrottleِ ساده (کلید بر اساسِ
# user.pk) توسطِ چرخشِ حساب مهمان قابل‌دورزدن بود. حالا از
# GuestAwareBazaarThrottle استفاده می‌شه که برای کاربرهای مهمان کلید
# رو بر اساسِ IP می‌سازه و برای کاربرهای غیرمهمان رفتارِ per-user
# قبلی رو دست‌نخورده نگه می‌داره. نرخ هم از ۲۰/hour به ۱۰/hour
# سخت‌گیرانه‌تر شد چون هر درخواستِ پذیرفته‌شده یک تماسِ سرور-به-سرورِ
# واقعی با بازار می‌زنه.
# این endpoint یک فراخوانیِ سرور-به-سرورِ واقعی به API بازار (verify_purchase)
# تریگر می‌کنه، برای همین throttle_scope مجزا و نرخِ سخت‌گیرانه‌تر (۱۰/hour)
# داره. کاربرهای مهمان با هر deviceId یک pk تازه می‌گیرن، پس
# GuestAwareBazaarThrottle برای اون‌ها بر اساسِ IP کلید می‌سازه تا چرخشِ
# حساب bucket تازه نگیره؛ برای کاربرهای غیرمهمان رفتارِ per-user حفظ می‌شه.
throttle_scope = 'bazaar_verify'
throttle_classes = [GuestAwareBazaarThrottle]
@@ -208,13 +181,10 @@ class BazaarVerifyPurchaseView(APIView):
serializer.is_valid(raise_exception=True)
v = serializer.validated_data
# ⚛️🔒 اصلاح: فراخوانی HTTP به API بازار (تا ~۲۰ ثانیه، دو درخواست
# پشت‌سرهم برای refresh token + verify) قبلاً *داخل* transaction.atomic
# و زیر select_for_update روی Order انجام می‌شد؛ یعنی ردیف Order (و
# هر تراکنش دیگه‌ای که بخواد همون Order یا Subscription مرتبط رو لمس
# کنه) تا برگشتِ پاسخ بازار قفل می‌موند. حالا verify_purchase قبل از
# باز شدن atomic/lock صدا زده می‌شه؛ لاک فقط برای اعمال نتیجه (چند
# میلی‌ثانیه) گرفته می‌شه.
# verify_purchase (تا ~۲۰ ثانیه، دو درخواستِ پشت‌سرهم) عمداً *قبل* از
# بازشدنِ atomic/lock صدا زده می‌شه، نه داخلش — وگرنه ردیفِ Order (و هر
# تراکنشِ دیگه‌ای روی همون Order/Subscription) تا برگشتِ پاسخِ بازار
# قفل می‌موند. لاک فقط برای اعمالِ نتیجه (چند میلی‌ثانیه) گرفته می‌شه.
order_lookup = get_object_or_404(
Order, pk=v['orderId'], user_id=request.user.id, provider='bazaar',
)