From aed02e36e5bb733945a92af797102048c72548bb Mon Sep 17 00:00:00 2001 From: Your Name <119736744+aborayan2022@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:21:42 +0200 Subject: [PATCH] fix: production CSRF, ProxyFix, and SSE streaming issues --- .gitignore | 2 +- backend/celerybeat-schedule | Bin 16384 -> 16384 bytes backend/data/dociva.db | Bin 0 -> 126976 bytes backend/data/saas_pdf.db | Bin 0 -> 241664 bytes backend/wsgi.py | 9 + docs/Docker-Commands-Guide.md | 725 ++++++++++++++++++++++ frontend/src/pages/ForgotPasswordPage.tsx | 11 +- frontend/src/pages/ResetPasswordPage.tsx | 12 +- frontend/src/services/api.ts | 20 +- nginx/nginx.prod.conf | 16 + 10 files changed, 773 insertions(+), 22 deletions(-) create mode 100644 backend/data/dociva.db create mode 100644 backend/data/saas_pdf.db create mode 100644 docs/Docker-Commands-Guide.md diff --git a/.gitignore b/.gitignore index 3505e5b..fb03365 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ docker-compose.override.yml uploads/ tmp/ *.tmp -backend/data/*.db +#backend/data/*.db # Logs *.log diff --git a/backend/celerybeat-schedule b/backend/celerybeat-schedule index f4d7d35e154f202b2fab00a3d3c0480d8277cc0d..a130f74e1035688637ceab771ca704a4202f2480 100644 GIT binary patch delta 28 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 A1poj5 literal 0 HcmV?d00001 diff --git a/backend/data/saas_pdf.db b/backend/data/saas_pdf.db new file mode 100644 index 0000000000000000000000000000000000000000..2d4675d8942e031880b53f6e0ca306858df7aeac GIT binary patch literal 241664 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 Pzz|>vFa#I^D navigate('/account'), 3000); } catch (err) { diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index efeac17..35ba4d1 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -412,13 +412,25 @@ export async function streamAssistantChat( payload: AssistantChatRequest, handlers: AssistantStreamHandlers = {} ): Promise { + // Ensure a CSRF token cookie exists before streaming + let csrfToken = getCookieValue(CSRF_COOKIE_NAME); + if (!csrfToken) { + await csrfBootstrapClient.get('/auth/csrf'); + csrfToken = getCookieValue(CSRF_COOKIE_NAME); + } + + const streamHeaders: Record = { + 'Content-Type': 'application/json', + Accept: 'text/event-stream', + }; + if (csrfToken) { + streamHeaders[CSRF_HEADER_NAME] = csrfToken; + } + const response = await fetch('/api/assistant/chat/stream', { method: 'POST', credentials: 'include', - headers: { - 'Content-Type': 'application/json', - Accept: 'text/event-stream', - }, + headers: streamHeaders, body: JSON.stringify(payload), }); diff --git a/nginx/nginx.prod.conf b/nginx/nginx.prod.conf index 26f612a..0d7fdad 100644 --- a/nginx/nginx.prod.conf +++ b/nginx/nginx.prod.conf @@ -67,6 +67,22 @@ server { gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml; gzip_min_length 1000; + # SSE streaming for assistant chat + location /api/assistant/chat/stream { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ''; + proxy_http_version 1.1; + proxy_buffering off; + proxy_cache off; + chunked_transfer_encoding off; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + } + # API requests → Flask location /api/ { proxy_pass http://backend;