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,