From 9c23fc6c5207e543bfc52e1b80bbf87ad414ff18 Mon Sep 17 00:00:00 2001
From: patrick-motsch
Date: Thu, 19 Feb 2026 00:46:42 +0100
Subject: [PATCH] fix: CSRF exemption for bot endpoints, WS ping timeout, clean
up debug logs
Co-authored-by: Cursor
---
app.py | 14 ++++++++++++++
modules/auth/csrf.py | 4 ++--
modules/features/teamsbot/service.py | 19 ++++++++++---------
3 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/app.py b/app.py
index 1eaf50a4..bc46ea35 100644
--- a/app.py
+++ b/app.py
@@ -570,3 +570,17 @@ from modules.system.registry import loadFeatureRouters
featureLoadResults = loadFeatureRouters(app)
logger.info(f"Feature router load results: {featureLoadResults}")
+
+# ============================================================================
+# LOCAL DEV / DIRECT RUN
+# ============================================================================
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(
+ "app:app",
+ host="0.0.0.0",
+ port=int(os.environ.get("PORT", "8000")),
+ ws_ping_interval=300,
+ ws_ping_timeout=300,
+ reload=True,
+ )
diff --git a/modules/auth/csrf.py b/modules/auth/csrf.py
index c29d6aec..40e33961 100644
--- a/modules/auth/csrf.py
+++ b/modules/auth/csrf.py
@@ -46,9 +46,9 @@ class CSRFMiddleware(BaseHTTPMiddleware):
if request.url.path in self.exempt_paths:
return await call_next(request)
- # Skip CSRF check for exempt path prefixes (bridge callbacks etc.)
+ # Skip CSRF check for exempt path prefixes (service-to-service callbacks)
if any(request.url.path.startswith(p) for p in self._exemptPrefixes):
- if "/bridge/" in request.url.path:
+ if "/bridge/" in request.url.path or "/bot/" in request.url.path:
return await call_next(request)
# Skip CSRF check for non-state-changing methods
diff --git a/modules/features/teamsbot/service.py b/modules/features/teamsbot/service.py
index 40c8962c..919b77fa 100644
--- a/modules/features/teamsbot/service.py
+++ b/modules/features/teamsbot/service.py
@@ -248,7 +248,7 @@ class TeamsbotService:
except Exception:
self._botAccountEmail = None
- logger.info(f"[WS-DEBUG] WebSocket handler started for session {sessionId}")
+ logger.info(f"[WS] Handler started for session {sessionId}")
try:
msgCount = 0
@@ -257,16 +257,17 @@ class TeamsbotService:
msgCount += 1
if "text" not in data:
- logger.debug(f"[WS-DEBUG] session={sessionId} msg #{msgCount}: non-text data received (keys: {list(data.keys())})")
+ logger.debug(f"[WS] session={sessionId} msg #{msgCount}: non-text data (keys: {list(data.keys())})")
continue
message = json.loads(data["text"])
msgType = message.get("type")
- logger.info(f"[WS-DEBUG] session={sessionId} msg #{msgCount}: type={msgType}")
+ if msgType not in ("audioChunk", "ping"):
+ logger.info(f"[WS] session={sessionId} msg #{msgCount}: type={msgType}")
if msgType == "transcript":
transcript = message.get("transcript", {})
- logger.info(f"[WS-DEBUG] Transcript received: speaker={transcript.get('speaker')}, text={transcript.get('text', '')[:60]}...")
+ logger.info(f"[WS] Transcript: speaker={transcript.get('speaker')}, text={transcript.get('text', '')[:60]}...")
await self._processTranscript(
sessionId=sessionId,
speaker=transcript.get("speaker", "Unknown"),
@@ -279,7 +280,7 @@ class TeamsbotService:
elif msgType == "chatMessage":
chat = message.get("chat", {})
- logger.info(f"[WS-DEBUG] Chat message received: speaker={chat.get('speaker')}, text={chat.get('text', '')[:60]}...")
+ logger.info(f"[WS] Chat: speaker={chat.get('speaker')}, text={chat.get('text', '')[:60]}...")
await self._processTranscript(
sessionId=sessionId,
speaker=chat.get("speaker", "Unknown"),
@@ -294,7 +295,7 @@ class TeamsbotService:
elif msgType == "status":
status = message.get("status")
errorMessage = message.get("message")
- logger.info(f"[WS-DEBUG] Status received: status={status}, message={errorMessage}")
+ logger.info(f"[WS] Status: status={status}, message={errorMessage}")
await self._handleBotStatus(sessionId, status, errorMessage, interface)
elif msgType == "audioChunk":
@@ -314,7 +315,7 @@ class TeamsbotService:
elif msgType == "voiceGreeting":
greetingText = message.get("text", "")
greetingLang = message.get("language", self.config.language)
- logger.info(f"[WS-DEBUG] Voice greeting request: text={greetingText[:60]}..., language={greetingLang}")
+ logger.info(f"[WS] Voice greeting: text={greetingText[:60]}..., language={greetingLang}")
if greetingText and voiceInterface:
try:
ttsResult = await voiceInterface.textToSpeech(
@@ -342,9 +343,9 @@ class TeamsbotService:
except Exception as e:
if "disconnect" not in str(e).lower():
- logger.error(f"[WS-DEBUG] WebSocket error for session {sessionId}: {type(e).__name__}: {e}")
+ logger.error(f"[WS] Error for session {sessionId}: {type(e).__name__}: {e}")
- logger.info(f"[WS-DEBUG] WebSocket handler ended for session {sessionId} after {msgCount} messages")
+ logger.info(f"[WS] Handler ended for session {sessionId} after {msgCount} messages")
async def _handleBotStatus(
self,