Fix: исправлена проверка доступа к чату при загрузке файлов

- Добавлена поддержка разных типов чатов (private, global, department, group)
- Для личных чатов проверяется участие через participants
- Для чатов отдела проверяется принадлежность к отделу
- Для глобального чата проверяется только is_active
- Для групповых/канальных чатов используется ChatMembership

Настройки CSRF:
- CSRF_COOKIE_HTTPONLY = False
- CSRF_COOKIE_SAMESITE = 'Lax'
- CSRF_USE_SESSIONS = False
This commit is contained in:
admin i 2025-11-28 08:04:09 +03:00
parent 6df487bd93
commit 446d59f0fa
3 changed files with 56 additions and 14 deletions

View File

@ -5,7 +5,7 @@ from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_POST
from communications.models import (
@ -16,9 +16,9 @@ from communications.models import (
)
@csrf_protect
@login_required
@require_POST
@ensure_csrf_cookie
def upload_message_with_attachments(request):
"""Отправка сообщения с вложениями"""
chat_id = request.POST.get('chat_id')
@ -33,18 +33,48 @@ def upload_message_with_attachments(request):
chat = get_object_or_404(Chat, pk=chat_id)
# Проверка доступа к чату
membership = ChatMembership.objects.filter(
chat=chat,
user=request.user,
is_active=True,
can_send_messages=True
).first()
if not membership:
return JsonResponse(
{'ok': False, 'error': 'Cannot send messages to this chat'},
status=403
)
# Для групповых, канальных и объявлений проверяем ChatMembership
if chat.type in ['group', 'channel', 'announcement']:
membership = ChatMembership.objects.filter(
chat=chat,
user=request.user,
is_active=True,
can_send_messages=True
).first()
if not membership:
return JsonResponse(
{'ok': False, 'error': 'Cannot send messages to this chat'},
status=403
)
# Для личных чатов проверяем, что пользователь - участник
elif chat.type == 'private':
if not chat.participants.filter(id=request.user.id).exists():
return JsonResponse(
{'ok': False, 'error': 'You are not a participant'},
status=403
)
# Для чатов отдела проверяем принадлежность к отделу
elif chat.type == 'department':
if chat.department:
from employees.models import EmployeeDepartment
is_member = EmployeeDepartment.objects.filter(
department=chat.department,
employee=request.user,
is_active=True
).exists()
if not is_member and chat.department.head_id != request.user.id:
return JsonResponse(
{'ok': False, 'error': 'Not a department member'},
status=403
)
# Глобальный чат доступен всем активным пользователям
elif chat.type == 'global':
if not request.user.is_active:
return JsonResponse(
{'ok': False, 'error': 'User is not active'},
status=403
)
# Если нет ни текста, ни файлов
if not content and not request.FILES:

View File

@ -191,6 +191,11 @@ CSRF_TRUSTED_ORIGINS = _split_env_list(
os.getenv("CSRF_TRUSTED_ORIGINS", "https://*.sytes.net")
)
# Настройки CSRF для AJAX запросов
CSRF_COOKIE_HTTPONLY = False # Позволяет JavaScript читать cookie
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_USE_SESSIONS = False
# -----------------------------------------------------------------------------
# EMAIL
# -----------------------------------------------------------------------------

View File

@ -360,6 +360,13 @@ document.addEventListener('DOMContentLoaded', function() {
formData.append('chat_id', '{{ chat.id }}');
const csrftoken = getCookie('csrftoken');
console.log('CSRF token:', csrftoken);
if (!csrftoken) {
console.error('CSRF token not found in cookies!');
alert('Ошибка: CSRF токен не найден. Обновите страницу.');
return;
}
try {
const response = await fetch('/api/v1/communications/upload-message/', {