throttling, abuse-protection & logging/monitoring pass

This commit is contained in:
2026-08-23 23:44:00 +03:30
parent cb18c93a3e
commit 80298b47b1
33 changed files with 4202 additions and 23 deletions

View File

@@ -3,6 +3,7 @@ from drf_spectacular.utils import extend_schema
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.throttling import ScopedRateThrottle
from rest_framework.views import APIView
from .models import AffiliateAccount, Conversion
@@ -14,6 +15,32 @@ from .serializers import (
)
class GuestAwareAffiliateThrottle(ScopedRateThrottle):
"""
⚠️ اضافه شده: همون الگویِ GuestAwareDiscountThrottle/GuestAwareFamilyThrottle
و بقیه؛ چرخشِ حسابِ مهمان (deviceId جدید → pk جدید) یک ScopedRateThrottleِ
سادهٔ per-user رو دور می‌زد. اینجا حساس‌تره چون referralCode یک
شناسه‌ی حدس‌زدنی‌ست (404 برای کدِ نامعتبر = oracle) و یک حدسِ درست
یک Conversion واقعی می‌سازه که به کمیسیونِ مالیِ affiliate صاحبِ کد
منجر می‌شه؛ یعنی بدونِ این throttle، چرخشِ حساب مهمان به مهاجم
guessهای عملاً نامحدودی برای enumerate/fraud کردنِ کدهای رفرال
می‌داد. برای کاربرهای مهمان کلیدِ cache از pk به IP کلاینت تغییر
می‌کنه؛ رفتارِ throttle برای کاربرهای غیرمهمان (per-user، مثلِ
قبل) دست‌نخورده می‌مونه.
"""
def get_cache_key(self, request, view):
user = request.user
if user and user.is_authenticated and getattr(user, 'is_guest', False):
ident = f'guest-ip:{self.get_ident(request)}'
elif user and user.is_authenticated:
ident = user.pk
else:
ident = self.get_ident(request)
return self.cache_format % {'scope': self.scope, 'ident': ident}
class AffiliateMeView(APIView):
"""GET /api/affiliate/me — حساب و کد ارجاع کاربر"""
@@ -48,6 +75,14 @@ class TrackConversionView(APIView):
"""
permission_classes = [IsAuthenticated]
# ⚠️ اضافه شده: قبلاً این endpoint هیچ throttleای نداشت؛ referralCode
# نامعتبر ۴۰۴ می‌گیره (یک oracle قابل‌probe) و حدسِ درست یک
# Conversion واقعیِ متصل به کمیسیونِ affiliate می‌سازه. طبقِ همون
# الگویِ بقیه‌ی اپ‌ها، throttle_scope مجزا با GuestAwareAffiliateThrottle
# اضافه شد تا هم probe کردنِ کد رو کند کنه، هم چرخشِ حساب مهمان
# دیگه bucket تازه نده.
throttle_scope = 'affiliate_track'
throttle_classes = [GuestAwareAffiliateThrottle]
@extend_schema(
request=TrackRequestSerializer, responses=TrackResponseSerializer, tags=['Affiliate (affiliate)']