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

@@ -12,13 +12,8 @@ from .models import Choice, Grade, Lesson, Node, NodeProgress, Question, Unit, U
class LessonCompleteImpossibleCountTests(TestCase):
"""
🔒 تستِ رگرسیونِ فیکسِ امنیتی: LessonCompleteView قبلاً correctCount رو
بدونِ مقایسه با تعدادِ واقعیِ سوال‌های درس می‌پذیرفت، پس یک کلاینتِ
مخرب می‌تونست با correctCount بزرگ‌تر از تعدادِ واقعیِ سوال‌ها،
xp/coins متورم بگیره. این تست هم ردِ درخواست‌های غیرممکن رو، هم
رفتارِ صحیحِ تکمیل با مقادیرِ معتبر رو تضمین می‌کنه.
"""
"""رگرسیون: correctCount باید با تعدادِ واقعیِ سوال‌های درس مقایسه بشه، وگرنه
کلاینتِ مخرب می‌تونه xp/coins رو متورم کنه."""
def setUp(self):
self.client = APIClient()
@@ -67,14 +62,9 @@ class LessonCompleteImpossibleCountTests(TestCase):
class LessonCompleteRatioIgnoresClientTotalQuestionsTests(TestCase):
"""
🔒 تستِ رگرسیونِ فیکسِ دوم: قبلاً ratio از totalQuestions ارسالی‌ی
خودِ کلاینت محاسبه می‌شد، نه از تعدادِ واقعیِ سوال‌های درس. یعنی حتی
بعد از سقف‌زدنِ correctCount، کلاینت می‌تونست با totalQuestions=1
(به‌جای ۳ سوالِ واقعی)، ratio رو مصنوعاً ۱۰۰٪ کنه و ۳ ستاره/coins
کامل بگیره درحالی‌که فقط ۱ از ۳ سوال رو درست جواب داده. حالا ratio
همیشه بر اساسِ actual_question_count محاسبه می‌شه.
"""
"""رگرسیون: ratio باید از actual_question_count محاسبه بشه نه از totalQuestیِ
ارسالیِ کلاینت، وگرنه حتی بعدِ سقف‌زدنِ correctCount کلاینت می‌تونه با
totalQuestions دروغین ratio رو مصنوعاً ۱۰۰٪ کنه."""
def setUp(self):
self.client = APIClient()
@@ -114,13 +104,8 @@ class LessonCompleteRatioIgnoresClientTotalQuestionsTests(TestCase):
class QuestionAnswerThrottleTests(TestCase):
"""
🔒 اثبات محدودیتِ جدیدِ per-user روی QuestionAnswerView
(throttle_scope='question_answer'): Idempotency-Key فقط جلوی retry با
همون کلید رو می‌گیره، نه حجمِ بالای درخواست‌های *متفاوت* که هرکدوم
یک UserAnswer جدید می‌سازن و منطقِ هارت/NodeProgress رو اجرا می‌کنن.
ScopedRateThrottle با pk کاربرِ احرازهویت‌شده کلید می‌خوره، نه IP.
"""
"""محدودیتِ per-user روی QuestionAnswerView (throttle_scope='question_answer')؛
Idempotency-Key فقط retry با همون کلید رو می‌گیره، نه حجمِ درخواست‌های متفاوت."""
def setUp(self):
from django.core.cache import cache
@@ -242,14 +227,8 @@ class QuestionAnswerThrottleTests(TestCase):
class LessonCompleteThrottleTests(TestCase):
"""
🔒 اثبات محدودیتِ جدیدِ per-user روی LessonCompleteView
(throttle_scope='lesson_complete'): Idempotency-Key فقط جلوی retry با
همون کلید رو می‌گیره، نه حجمِ بالای درخواست‌های *متفاوت* که هرکدوم
یک UserLessonCompletion جدید می‌سازن و سیگنالِ post_save
(NodeProgress) + به‌روزرسانیِ UserStats رو اجرا می‌کنن.
ScopedRateThrottle با pk کاربرِ احرازهویت‌شده کلید می‌خوره، نه IP.
"""
"""محدودیتِ per-user روی LessonCompleteView (throttle_scope='lesson_complete')؛
Idempotency-Key فقط retry با همون کلید رو می‌گیره، نه حجمِ درخواست‌های متفاوت."""
def setUp(self):
from django.core.cache import cache
@@ -361,17 +340,9 @@ class LessonCompleteThrottleTests(TestCase):
class QuestionAnswerGuestThrottleBypassTests(TestCase):
"""
🔒 اثبات فیکسِ امنیتی: قبلاً کلیدِ throttle_scope='question_answer' برای
هر کاربرِ احرازهویت‌شده (مهمان یا نه) user.pk بود. چون GuestSessionView
با هر deviceId جدید یک کاربرِ مهمانِ تازه (pk جدید) می‌سازه، یک مهاجم
می‌تونست با ساختنِ پی‌درپیِ حساب‌های مهمان، هر بار یک bucket throttle
تازه بگیره و منطقِ هارت/NodeProgress رو بی‌محدودیت اجرا کنه. حالا
GuestAwareContentThrottle برای کاربرهای مهمان کلید رو بر اساسِ IP
(همون get_ident که guest_session هم استفاده می‌کنه) می‌سازه، پس چرخشِ
حساب مهمان دیگه bucket تازه نمی‌ده. رفتارِ throttle برای کاربرِ
غیرمهمان (per-user، مثلِ قبل) دست‌نخورده مونده.
"""
"""اثباتِ فیکسِ throttle: چرخشِ حساب مهمان (هر deviceId یه pk تازه) نباید
bucket تازه‌ی question_answer بده — GuestAwareContentThrottle برای
مهمان‌ها کلید رو بر اساسِ IP می‌سازه، نه user.pk."""
def setUp(self):
from django.core.cache import cache
@@ -446,17 +417,9 @@ class QuestionAnswerGuestThrottleBypassTests(TestCase):
class LessonCompleteGuestThrottleBypassTests(TestCase):
"""
🔒 اثبات فیکسِ امنیتی: قبلاً کلیدِ throttle_scope='lesson_complete' برای
هر کاربرِ احرازهویت‌شده (مهمان یا نه) user.pk بود. چون GuestSessionView
با هر deviceId جدید یک کاربرِ مهمانِ تازه (pk جدید) می‌سازه، یک مهاجم
می‌تونست با ساختنِ پی‌درپیِ حساب‌های مهمان، هر بار یک bucket throttle
تازه بگیره و UserLessonCompletion/xp/coins/progress رو بی‌محدودیت
تولید کنه. حالا GuestAwareContentThrottle برای کاربرهای مهمان کلید رو
بر اساسِ IP می‌سازه، پس چرخشِ حساب مهمان دیگه bucket تازه نمی‌ده.
رفتارِ throttle برای کاربرِ غیرمهمان (per-user، مثلِ قبل) دست‌نخورده
مونده.
"""
"""اثباتِ فیکسِ throttle: چرخشِ حساب مهمان نباید bucket تازه‌ی
lesson_complete بده — GuestAwareContentThrottle برای مهمان‌ها کلید رو
بر اساسِ IP می‌سازه، نه user.pk."""
def setUp(self):
from django.core.cache import cache