throttling, abuse-protection & logging/monitoring pass
This commit is contained in:
@@ -2,6 +2,7 @@ from django.shortcuts import get_object_or_404
|
||||
from drf_spectacular.utils import extend_schema
|
||||
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 BugReport, Ticket, TicketMessage
|
||||
@@ -16,10 +17,57 @@ from .serializers import (
|
||||
)
|
||||
|
||||
|
||||
class GuestAwareSupportThrottle(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 'support_create'
|
||||
بگیره. چون هر سه Endpointِ این اپ (BugReportCreateView،
|
||||
TicketCreateView، TicketMessageCreateView) این scope رو بهاشتراک
|
||||
میذارن و هرکدوم واقعاً یک رکورد در دیتابیس میسازن (BugReport،
|
||||
Ticket، یا TicketMessage)، چرخشِ حساب مهمان میتونست محدودیتِ
|
||||
۳/ساعتِ در نظر گرفتهشده رو چند برابر کنه و باعثِ spam بشه.
|
||||
|
||||
این کلاسِ throttle یکبار اینجا تعریف شده و بینِ هر سه Endpoint
|
||||
بهاشتراک گذاشته میشه (بهجایِ تکرارِ یک کلاسِ مشابه برای هرکدوم)،
|
||||
دقیقاً چون هر سه از یک throttle_scope مشترک استفاده میکنن. فقط
|
||||
برای کاربرهای مهمان (is_guest=True) کلیدِ cache از pk کاربر به IP
|
||||
کلاینت (get_ident) تغییر میکنه، پس همهی حسابهای مهمانِ ساختهشده
|
||||
از یک IP یک bucket مشترک دارن و چرخشِ حساب دیگه bucket تازه نمیده.
|
||||
رفتارِ throttle برای کاربرهای غیرمهمان (ثبتنامشده) دقیقاً مثلِ قبل
|
||||
(کلید بر اساسِ pk) باقی میمونه؛ منطقِ ساختِ رکورد/ownership/serializer
|
||||
در هر سه ویو دستنخوردهست.
|
||||
"""
|
||||
|
||||
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 BugReportCreateView(APIView):
|
||||
"""POST /api/support/bug-reports — ثبت گزارش باگ"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
# هیچ مکانیزمِ idempotency ای اینجا نیست، پس بدونِ throttle یک کاربرِ
|
||||
# احرازهویتشده میتونه تعدادِ نامحدودی BugReport با درخواستهای
|
||||
# پرتکرار بسازه. ScopedRateThrottle با pk کاربر کلید میخوره (نه IP).
|
||||
# ⚠️ اصلاح شده: چون کاربرهای مهمان با هر deviceId جدید یک pk تازه
|
||||
# میگیرن، از GuestAwareSupportThrottle استفاده میشه تا چرخشِ حساب
|
||||
# مهمان دیگه bucket تازه ندهد (نگاه کنید به تعریفِ کلاس بالا).
|
||||
throttle_scope = 'support_create'
|
||||
throttle_classes = [GuestAwareSupportThrottle]
|
||||
|
||||
@extend_schema(
|
||||
request=BugReportCreateRequestSerializer,
|
||||
@@ -46,6 +94,13 @@ class TicketCreateView(APIView):
|
||||
"""POST /api/support/tickets — ایجاد تیکت"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
# مثلِ BugReportCreateView: هیچ idempotency ای نیست، پس این endpoint هم
|
||||
# همون scope=support_create رو بهاشتراک میذاره تا محدودیتِ ساختِ
|
||||
# رکوردهای پشتیبانی، مستقل از اینکه کدوم نوع رکورده، رعایت بشه.
|
||||
# ⚠️ اصلاح شده: از همون GuestAwareSupportThrottleِ مشترک استفاده میشه
|
||||
# تا چرخشِ حساب مهمان bucket تازه ندهد.
|
||||
throttle_scope = 'support_create'
|
||||
throttle_classes = [GuestAwareSupportThrottle]
|
||||
|
||||
@extend_schema(
|
||||
request=TicketCreateRequestSerializer,
|
||||
@@ -107,6 +162,12 @@ class TicketMessageCreateView(APIView):
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
# مثلِ دو Endpoint بالا: بدونِ throttle، یک کاربر میتونست تعدادِ
|
||||
# نامحدودی پیام در یک تیکت بسازه.
|
||||
# ⚠️ اصلاح شده: از همون GuestAwareSupportThrottleِ مشترک استفاده میشه
|
||||
# تا چرخشِ حساب مهمان bucket تازه ندهد.
|
||||
throttle_scope = 'support_create'
|
||||
throttle_classes = [GuestAwareSupportThrottle]
|
||||
|
||||
@extend_schema(
|
||||
request=TicketMessageCreateRequestSerializer,
|
||||
|
||||
Reference in New Issue
Block a user