fix: WeasyPrint URL fetcher + attachment improvements + webhook error propagation + WebSocket conversation check + RLS disabled on system tables (bootstrap fix)
Check Cross-Plugin Imports / check (push) Has been cancelled

This commit is contained in:
Agent Zero
2026-07-29 13:19:21 +02:00
parent 9bd6936d17
commit f1a2484055
6 changed files with 119 additions and 9 deletions
+17 -1
View File
@@ -515,7 +515,23 @@ async def websocket_endpoint(
elif msg_type == "subscribe":
conv_id = msg.get("conversation_id")
if conv_id:
ws_manager.subscribe(conv_id, user_id)
# P1.9 fix: Check if user is a participant of this conversation
from app.core.db import async_session_maker
from sqlalchemy import text as sql_text
try:
async with async_session_maker() as db:
await db.execute(sql_text("SELECT set_config('app.current_tenant_id', :tid, true)"), {"tid": tenant_id})
result = await db.execute(
sql_text("SELECT 1 FROM conversation_participants WHERE conversation_id = :cid AND user_id = :uid"),
{"cid": conv_id, "uid": user_id},
)
if result.first():
ws_manager.subscribe(conv_id, user_id)
else:
await ws_manager.send_to_user(user_id, {"type": "error", "message": "Not a participant of this conversation"})
except Exception:
logger.warning("Failed to check conversation participation for %s in %s", user_id, conv_id)
await ws_manager.send_to_user(user_id, {"type": "error", "message": "Cannot verify participation"})
elif msg_type == "unsubscribe":
conv_id = msg.get("conversation_id")
if conv_id:
@@ -130,9 +130,23 @@ def render_template_string(template_content: str, data: dict[str, Any]) -> str:
return template.render(**data)
def _safe_url_fetcher(url: str, timeout: int = 10) -> dict:
"""URL fetcher that only allows data: URIs and blocks external resources.
Prevents SSRF and local file access via WeasyPrint.
"""
if url.startswith('data:'):
from weasyprint import default_url_fetcher
return default_url_fetcher(url, timeout)
# Block all external URLs (http, https, file, etc.)
raise ValueError(f"External resource blocked by URL fetcher: {url}")
def generate_pdf(html_content: str) -> bytes:
"""Generate a PDF from HTML content using WeasyPrint.
Uses a safe URL fetcher that blocks external resources (SSRF protection).
Args:
html_content: Valid HTML string
@@ -141,7 +155,7 @@ def generate_pdf(html_content: str) -> bytes:
"""
from weasyprint import HTML
pdf = HTML(string=html_content).write_pdf()
pdf = HTML(string=html_content, url_fetcher=_safe_url_fetcher).write_pdf()
return pdf