From 7697673a3b89245d5c49467e50fedd4c22cf9852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Mon, 12 Oct 2026 22:52:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=93=81=E7=89=8C=E4=B8=8B=E5=8F=91?= =?UTF-8?q?=E5=AE=A1=E6=9F=A5=E4=BF=AE=E5=A4=8D=EF=BC=88esc=E7=BB=9F?= =?UTF-8?q?=E4=B8=80/=E8=AF=AD=E6=96=99=E4=B8=AD=E6=80=A7=E5=8C=96/?= =?UTF-8?q?=E7=A9=BF=E8=B6=8A=E5=8A=A0=E5=9B=BA/=E5=8F=8D=E5=90=91?= =?UTF-8?q?=E6=96=AD=E8=A8=80=E5=8A=A8=E6=80=81=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- app/engine/routes/chat.py | 10 +++-- app/engine/routes/public.py | 5 +++ static/chat.html | 2 +- static/js/chat.js | 16 +++----- static/widget-test.html | 14 ++++--- static/widget.js | 12 +++--- tests/test_brand_endpoint.py | 43 +++++++++++++++++++- tests/test_widget_namespacing.py | 69 ++++++++++++++++++++++++++++---- 8 files changed, 137 insertions(+), 34 deletions(-) diff --git a/app/engine/routes/chat.py b/app/engine/routes/chat.py index e49494f..bf3acb5 100644 --- a/app/engine/routes/chat.py +++ b/app/engine/routes/chat.py @@ -49,10 +49,9 @@ async def ws_chat(websocket: WebSocket): init_msg = json.loads(init_data) # Task 10: 客户端自报 site(空域名站点如 es 靠嵌入代码 data-site - # 接入)记入 client_info 作会话站点标——只加记录,不参与业务逻辑 + # 接入)作会话站点标——只加记录,不参与业务逻辑;写入点在下方 + # 新建会话处(优先级对齐 REST,见那里注释) site_slug = str(init_msg.get("site") or "").strip() - if site_slug: - client_info["site"] = site_slug if "session_id" in init_msg: conv = await manager.get_by_session(init_msg["session_id"]) @@ -84,6 +83,11 @@ async def ws_chat(websocket: WebSocket): # 无 XFF 时保留客户端自报,user_agent 等其他字段不受影响 if forwarded: merged_info["ip"] = forwarded + # Task 10 复审: 专用 site 字段同样赢过 init_msg.client_info + # 自报的 site(与 REST ?site= 覆盖 req.client_info 的优先级 + # 对齐——专用通道是嵌入代码显式声明,可信度高于任意自报 dict) + if site_slug: + merged_info["site"] = site_slug conv = await manager.create_conversation( source=source, client_info=merged_info, diff --git a/app/engine/routes/public.py b/app/engine/routes/public.py index 1f40b62..0f8d944 100644 --- a/app/engine/routes/public.py +++ b/app/engine/routes/public.py @@ -76,6 +76,11 @@ async def avatar(request: Request): # "/static/kefu-small.png" 这类路径,取基名后拼租户 assets 目录,无路径 # 逃逸面(单成分文件名不可能越出 assets/) name = pathlib.PurePosixPath(str(site.brand.get("avatar") or "")).name + # 复审加固: PurePosixPath 不认反斜杠(整串留在 .name 里),Windows 文件 + # 系统却把反斜杠当分隔符——seed_dir/assets/.. 会真穿出资产目录 serve + # 任意文件。显式拒绝分隔符与目录点,命中即回退静态兜底。 + if name in {".", ".."} or "/" in name or "\\" in name: + name = "" candidate = runtime.seed_dir / "assets" / name if name else None if candidate is not None and candidate.is_file(): return FileResponse( diff --git a/static/chat.html b/static/chat.html index afcb8d2..3a95cc6 100644 --- a/static/chat.html +++ b/static/chat.html @@ -30,7 +30,7 @@
How can we help?
-
Ask about pipe specifications, quotations, MOQ, shipping and delivery.
+
Ask about products, quotations, MOQ, shipping and delivery.