Harden security

This commit is contained in:
2026-03-05 05:42:19 +00:00
parent 06735bdfb1
commit 438e561da0
75 changed files with 6260 additions and 278 deletions

View File

@@ -17,6 +17,10 @@ from django.core.cache import cache
from core.clients import ClientBase, transport
from core.messaging import history, media_bridge, reply_sync
from core.models import Message, PersonIdentifier, PlatformChatLink
from core.security.attachments import (
validate_attachment_metadata,
validate_attachment_url,
)
try:
from google.protobuf.json_format import MessageToDict
@@ -3141,31 +3145,42 @@ class WhatsAppClient(ClientBase):
if isinstance(content, memoryview):
content = content.tobytes()
if isinstance(content, bytes):
filename, content_type = validate_attachment_metadata(
filename=(attachment or {}).get("filename") or "attachment.bin",
content_type=(attachment or {}).get("content_type")
or "application/octet-stream",
size=len(content),
)
return {
"content": content,
"filename": (attachment or {}).get("filename") or "attachment.bin",
"content_type": (attachment or {}).get("content_type")
or "application/octet-stream",
"filename": filename,
"content_type": content_type,
"size": len(content),
}
url = (attachment or {}).get("url")
if url:
safe_url = validate_attachment_url(url)
timeout = aiohttp.ClientTimeout(total=20)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.get(url) as response:
async with session.get(safe_url) as response:
if response.status != 200:
return None
payload = await response.read()
return {
"content": payload,
"filename": (attachment or {}).get("filename")
or url.rstrip("/").split("/")[-1]
filename, content_type = validate_attachment_metadata(
filename=(attachment or {}).get("filename")
or safe_url.rstrip("/").split("/")[-1]
or "attachment.bin",
"content_type": (attachment or {}).get("content_type")
content_type=(attachment or {}).get("content_type")
or response.headers.get(
"Content-Type", "application/octet-stream"
),
size=len(payload),
)
return {
"content": payload,
"filename": filename,
"content_type": content_type,
"size": len(payload),
}
return None
@@ -3320,11 +3335,19 @@ class WhatsAppClient(ClientBase):
payload = await self._fetch_attachment_payload(attachment)
if not payload:
continue
mime = str(
payload.get("content_type") or "application/octet-stream"
).lower()
data = payload.get("content") or b""
filename = payload.get("filename") or "attachment.bin"
try:
filename, mime = validate_attachment_metadata(
filename=payload.get("filename") or "attachment.bin",
content_type=payload.get("content_type")
or "application/octet-stream",
size=payload.get("size")
or (len(data) if isinstance(data, (bytes, bytearray)) else 0),
)
except Exception as exc:
self.log.warning("whatsapp blocked attachment: %s", exc)
continue
mime = str(mime).lower()
attachment_target = jid_obj if jid_obj is not None else jid
send_method = "document"
if mime.startswith("image/") and hasattr(self._client, "send_image"):
@@ -3372,7 +3395,7 @@ class WhatsAppClient(ClientBase):
sent_ts,
self._normalize_timestamp(self._pluck(response, "Timestamp") or 0),
)
await _record_bridge(response, sent_ts, body_hint=filename)
await _record_bridge(response, sent_ts, body_hint="attachment")
sent_any = True
if getattr(settings, "WHATSAPP_DEBUG", False):
self.log.debug(