Security review fixes: admin permissions, guest sessions, payment edge cases, assistant leaks
- Admin: refund/cancel/mark-resolved/Bazaar-link actions need change permission; question and curriculum import need add/delete; content browser needs view_question; guest device ids are shown to superusers only. - Accounts: registering a guest's phone revokes the guest's earlier sessions; self-deletion keeps Redemption, UserOffer and the phone's OTP rows; the public demo guest cannot be deleted (DEMO_GUEST_DEVICE_IDS); display-name contact filter covers any separator and social handles. - Payment: callback without Authority is 400; a second Bazaar purchase on a paid order is 409; orders snapshot credits/hearts/days at creation (payment.0011). - Assistant: a broken diagram no longer makes a streamed answer free; a late off-topic marker refuses the answer (not stored, not cached); a disconnect saves the partial answer; only KNOWN_COLLECTIONS are searched. - Infra: secret-key file is created atomically (workers no longer split keys); no default INTERNAL_SERVICE_KEY; Kavenegar key and Bazaar token kept out of error logs; Swagger/ReDoc pinned; schema throttled; docker compose bound to 127.0.0.1; non-ASCII digit ids are 400; ticket text capped at 5000. - docs/security-before-production.md: remaining open items 24-31 and the guard tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,9 +10,12 @@
|
||||
گزارشهای بازِ کاربران، و درصدِ پاسخِ غلط — یعنی همان سیگنالی که میگوید کدام
|
||||
سوال ایراد دارد یا بیش از حد سخت است.
|
||||
|
||||
فقط برای کارمندی که اجازهی دیدنِ سوال دارد، چون کلیدِ جوابها را نشان میدهد.
|
||||
|
||||
وابستگیِ تازهای اضافه نمیکند: چند اندپوینتِ کوچکِ JSON و JavaScript ساده.
|
||||
"""
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.db.models import Count, Q
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render
|
||||
@@ -22,6 +25,7 @@ from .models import Grade, Lesson, Node, Question, Unit
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@permission_required('content.view_question', raise_exception=True)
|
||||
def browser_view(request):
|
||||
return render(request, 'admin/content/browser.html', {
|
||||
'title': 'مرورِ محتوا',
|
||||
@@ -30,6 +34,7 @@ def browser_view(request):
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@permission_required('content.view_question', raise_exception=True)
|
||||
def units_json(request, grade_id: int):
|
||||
rows = (
|
||||
Unit.objects.filter(grade_id=grade_id)
|
||||
@@ -41,6 +46,7 @@ def units_json(request, grade_id: int):
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@permission_required('content.view_question', raise_exception=True)
|
||||
def nodes_json(request, unit_id: int):
|
||||
rows = (
|
||||
Node.objects.filter(unit_id=unit_id)
|
||||
@@ -52,6 +58,7 @@ def nodes_json(request, unit_id: int):
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@permission_required('content.view_question', raise_exception=True)
|
||||
def lessons_json(request, node_id: int):
|
||||
rows = (
|
||||
Lesson.objects.filter(node_id=node_id)
|
||||
@@ -63,6 +70,7 @@ def lessons_json(request, node_id: int):
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@permission_required('content.view_question', raise_exception=True)
|
||||
def questions_json(request, lesson_id: int):
|
||||
"""
|
||||
هر سوال با دو سیگنال: گزارشِ بازِ کاربران، و درصدِ پاسخِ غلط.
|
||||
|
||||
Reference in New Issue
Block a user