harden OTP for real SMS and close the second audit round
Kavenegar is being switched on, so every OTP request now costs credit: - phone numbers are normalised to 09XXXXXXXXX everywhere (login, OTP, family invite, TEST_LOGIN_PHONES keys) and existing rows are migrated; non-Iranian and landline numbers are rejected before any SMS - cooldown and a daily per-phone cap are counted in the database, so the three gunicorn workers no longer triple them - a global daily OTP SMS cap (default 300) stops SMS pumping - per-IP rates widened for CGNAT / school Wi-Fi (env-overridable) - provider message id is logged; SMS text warns not to share the code Second audit round: an offer no longer shortens a longer paid plan, Zarinpal error bodies no longer 500, island XP reaches the parent report, a non-numeric questionId no longer 500s after the answer is generated. 596 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,12 +98,21 @@ def _is_db_ref_id(value) -> bool:
|
||||
این تابع فقط تشخیص میده که آیا مقدار برای ذخیرهسازی در همچین
|
||||
فیلدی امن/عددی هست یا نه؛ روی مرزِ generate_tutor_answer اثری نداره
|
||||
(اونجا همیشه مقدارِ خامِ اصلی پاس داده میشه).
|
||||
|
||||
پیامِ دستیار هم از همین مسیر (`_db_ref_or_none`) رد میشود؛ پیش از
|
||||
۲۰۲۶-۰۹-۲۵ نمیشد و questionIdِ غیرعددی *بعد از* تولیدِ جواب ۵۰۰ میداد و
|
||||
سهمِ روزانه مصرفشده میماند.
|
||||
"""
|
||||
if value in (None, ''):
|
||||
return False
|
||||
return str(value).strip().lstrip('-').isdigit()
|
||||
|
||||
|
||||
def _db_ref_or_none(value):
|
||||
"""مقدارِ عددی برای ستونِ IntegerField، وگرنه None (نه خطای ORM)."""
|
||||
return value if _is_db_ref_id(value) else None
|
||||
|
||||
|
||||
def _conversation_history(conversation, before_message) -> list[dict]:
|
||||
"""
|
||||
چند پیامِ آخرِ همین گفتگو، پیش از سوالِ تازه، به ترتیبِ زمان.
|
||||
@@ -419,7 +428,7 @@ class AskAIView(APIView):
|
||||
conversation=conversation,
|
||||
role='assistant',
|
||||
text=answer_text,
|
||||
question_id=v.get('questionId') or None,
|
||||
question_id=_db_ref_or_none(v.get('questionId')),
|
||||
**_annotation(retrieval_meta, generation_meta, from_cache=answer_from_cache),
|
||||
)
|
||||
|
||||
@@ -558,7 +567,7 @@ class AskAIView(APIView):
|
||||
with transaction.atomic():
|
||||
assistant_message = Message.objects.create(
|
||||
conversation=conversation, role='assistant', text=answer_text,
|
||||
question_id=v.get('questionId') or None,
|
||||
question_id=_db_ref_or_none(v.get('questionId')),
|
||||
**_annotation(retrieval_meta, generation_meta, from_cache=answer_from_cache),
|
||||
)
|
||||
if idempotency_key:
|
||||
|
||||
Reference in New Issue
Block a user