From 45b5a971f57c79c0bd62ded5796a9f8d2908b271 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Wed, 9 Sep 2026 11:05:49 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20Internationalization=20(i18n)=20for=20I?= =?UTF-8?q?n=E2=80=91line=20Error=20Prompts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/apps/system/api/assistant.py | 31 ++++++++++++++++++---------- backend/locales/en.json | 12 ++++++++++- backend/locales/ko-KR.json | 12 ++++++++++- backend/locales/zh-CN.json | 12 ++++++++++- backend/locales/zh-TW.json | 12 ++++++++++- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/backend/apps/system/api/assistant.py b/backend/apps/system/api/assistant.py index fb81a846..d35da977 100644 --- a/backend/apps/system/api/assistant.py +++ b/backend/apps/system/api/assistant.py @@ -40,53 +40,62 @@ async def info(request: Request, response: Response, session: SessionDep, trans: # 校验 SQLBOT-EMBEDDED-SIGN 请求头 sign_header = request.headers.get("SQLBOT-EMBEDDED-SIGN") if not sign_header: - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin='')) + raise RuntimeError(trans('i18n_embedded.missing_sign')) - sign_data = await decrypt_embedded_sign(sign_header) + try: + sign_data = await decrypt_embedded_sign(sign_header) + except Exception: + raise RuntimeError(trans('i18n_embedded.invalid_sign')) # 校验 assistant_id 与 id 参数一致 if str(sign_data.get("assistant_id")) != str(id): - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin='')) + raise RuntimeError(trans('i18n_embedded.assistant_id_mismatch')) # 校验 target(来源域名)是否合法 target = sign_data.get("target", "") request_origin = request.headers.get("origin") or get_origin_from_referer(request) if not request_origin: - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=request_origin or '')) + raise RuntimeError(trans('i18n_embedded.missing_origin')) request_origin = request_origin.rstrip('/') if not target or target == "null": target = request_origin elif target != request_origin: - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) + raise RuntimeError(trans('i18n_embedded.target_origin_mismatch')) if not origin_match_domain(target, db_model.domain): raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) # 校验 sign_time 是否在 10 秒内 sign_time_str = sign_data.get("sign_time", "") - sign_time = datetime.fromisoformat(sign_time_str) + try: + sign_time = datetime.fromisoformat(sign_time_str) + except (ValueError, TypeError): + raise RuntimeError(trans('i18n_embedded.sign_time_invalid')) now_utc = datetime.now(timezone.utc) sign_time_utc = sign_time.astimezone(timezone.utc) if abs((now_utc - sign_time_utc).total_seconds()) > 10: - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) + raise RuntimeError(trans('i18n_embedded.sign_time_expired')) # 校验是否为真实浏览器请求(非自动化工具) if sign_data.get("webdriver", False): - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) + raise RuntimeError(trans('i18n_embedded.automation_tool_detected')) # 校验 User-Agent 一致性(签名中的 navigator.userAgent 与请求头一致) sign_user_agent = sign_data.get("user_agent", "") request_user_agent = request.headers.get("User-Agent", "") if sign_user_agent != request_user_agent: - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) + raise RuntimeError(trans('i18n_embedded.user_agent_mismatch')) # 校验 timezone 与 sign_time 偏移一致性(防时区伪造) tz_name = sign_data.get("timezone", "") - tz = ZoneInfo(tz_name) + try: + tz = ZoneInfo(tz_name) + except Exception: + raise RuntimeError(trans('i18n_embedded.timezone_mismatch')) sign_time_naive = sign_time.replace(tzinfo=None) if tz.utcoffset(sign_time_naive) != sign_time.utcoffset(): - raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=target or '')) + raise RuntimeError(trans('i18n_embedded.timezone_mismatch')) origin = target.rstrip('/') diff --git a/backend/locales/en.json b/backend/locales/en.json index 08ab4bcc..d40e9d81 100644 --- a/backend/locales/en.json +++ b/backend/locales/en.json @@ -54,7 +54,17 @@ "i18n_ds_invalid": "Datasource connection is invalid", "i18n_ds_upload_error": "Upload Failed", "i18n_embedded": { - "invalid_origin": "Domain name validation failed【{origin}】" + "invalid_origin": "Domain name validation failed【{origin}】", + "missing_sign": "Missing embedded signature (SQLBOT-EMBEDDED-SIGN); cannot verify the embedding party's identity.", + "assistant_id_mismatch": "The assistant ID in the signature does not match the current request; cannot verify the embedding party's identity.", + "missing_origin": "The current page is missing source information (Origin/Referer); cannot verify the embedding party's identity.", + "target_origin_mismatch": "The source domain in the signature does not match the current page domain; cannot verify the embedding party's identity.", + "invalid_sign": "The embedded signature is invalid or corrupted; cannot verify the embedding party's identity.", + "sign_time_expired": "The synchronization delay between the server (SQLBot) and the current page (embedding site) exceeds 10 seconds, causing the connection to be interrupted.", + "sign_time_invalid": "Invalid signature time format; cannot verify the embedding party's identity.", + "automation_tool_detected": "Automated tool access detected. Embedding has been blocked.", + "user_agent_mismatch": "The browser identifier in the signature does not match the current request. Embedding has been blocked.", + "timezone_mismatch": "The timezone information in the signature does not match the signing time. Embedding has been blocked." }, "i18n_chat": { "record_id_in_mcp": "Answer ID: " diff --git a/backend/locales/ko-KR.json b/backend/locales/ko-KR.json index d12b70d3..71e58fa6 100644 --- a/backend/locales/ko-KR.json +++ b/backend/locales/ko-KR.json @@ -54,7 +54,17 @@ "i18n_ds_invalid": "데이터 소스 연결이 무효합니다", "i18n_ds_upload_error": "파일 업로드 실패", "i18n_embedded": { - "invalid_origin": "도메인 이름 검증 실패 【{origin}】" + "invalid_origin": "도메인 이름 검증 실패 【{origin}】", + "missing_sign": "임베드 서명(SQLBOT-EMBEDDED-SIGN)이 누락되어 임베드 당사자의 신원을 확인할 수 없습니다.", + "assistant_id_mismatch": "서명의 어시스턴트 ID가 현재 요청과 일치하지 않아 임베드 당사자의 신원을 확인할 수 없습니다.", + "missing_origin": "현재 페이지에 출처 정보(Origin/Referer)가 없어 임베드 당사자의 신원을 확인할 수 없습니다.", + "target_origin_mismatch": "서명의 출처 도메인이 현재 페이지 도메인과 일치하지 않아 임베드 당사자의 신원을 확인할 수 없습니다.", + "invalid_sign": "임베드 서명이 유효하지 않거나 손상되어 임베드 당사자의 신원을 확인할 수 없습니다.", + "sign_time_expired": "서버(SQLBot)와 현재 페이지(임베드 사이트) 간 동기화 지연이 10초를 초과하여 연결이 중단되었습니다.", + "sign_time_invalid": "서명 시간 형식이 유효하지 않아 임베드 당사자의 신원을 확인할 수 없습니다.", + "automation_tool_detected": "자동화 도구 접근이 감지되어 임베드를 차단했습니다.", + "user_agent_mismatch": "서명의 브라우저 식별 정보가 현재 요청과 일치하지 않아 임베드를 차단했습니다.", + "timezone_mismatch": "서명의 시간대 정보가 서명 시간과 일치하지 않아 임베드를 차단했습니다." }, "i18n_chat": { "record_id_in_mcp": "응답 ID: " diff --git a/backend/locales/zh-CN.json b/backend/locales/zh-CN.json index 2fa8744c..7c147b0d 100644 --- a/backend/locales/zh-CN.json +++ b/backend/locales/zh-CN.json @@ -54,7 +54,17 @@ "i18n_ds_invalid": "数据源连接无效", "i18n_ds_upload_error": "上传文件失败", "i18n_embedded": { - "invalid_origin": "域名校验失败【{origin}】" + "invalid_origin": "域名校验失败【{origin}】", + "missing_sign": "缺少嵌入签名(SQLBOT-EMBEDDED-SIGN),无法验证嵌入方身份。", + "assistant_id_mismatch": "签名中的助手标识与当前请求不一致,无法验证嵌入方身份。", + "missing_origin": "当前页面缺少来源信息(Origin/Referer),无法验证嵌入方身份。", + "target_origin_mismatch": "签名中的来源域名与当前页面域名不一致,无法验证嵌入方身份。", + "invalid_sign": "嵌入签名无效或已损坏,无法验证嵌入方身份。", + "sign_time_expired": "服务端(SQLBot)与当前页面(嵌入端)的同步延迟超过10秒,导致连接中断。", + "sign_time_invalid": "签名时间格式无效,无法验证嵌入方身份。", + "automation_tool_detected": "检测到自动化工具访问,已阻止嵌入。", + "user_agent_mismatch": "签名中的浏览器标识与当前请求不一致,已阻止嵌入。", + "timezone_mismatch": "签名中的时区信息与签名时间不一致,已阻止嵌入。" }, "i18n_chat": { "record_id_in_mcp": "响应ID: " diff --git a/backend/locales/zh-TW.json b/backend/locales/zh-TW.json index 3a5358ab..24f98a22 100644 --- a/backend/locales/zh-TW.json +++ b/backend/locales/zh-TW.json @@ -54,7 +54,17 @@ "i18n_ds_invalid": "數據源連接無效", "i18n_ds_upload_error": "上傳文件失敗", "i18n_embedded": { - "invalid_origin": "網域校驗失敗【{origin}】" + "invalid_origin": "網域校驗失敗【{origin}】", + "missing_sign": "缺少嵌入簽名(SQLBOT-EMBEDDED-SIGN),無法驗證嵌入方身分。", + "assistant_id_mismatch": "簽名中的助手標識與當前請求不一致,無法驗證嵌入方身分。", + "missing_origin": "當前頁面缺少來源資訊(Origin/Referer),無法驗證嵌入方身分。", + "target_origin_mismatch": "簽名中的來源網域與當前頁面網域不一致,無法驗證嵌入方身分。", + "invalid_sign": "嵌入簽名無效或已損壞,無法驗證嵌入方身分。", + "sign_time_expired": "服務端(SQLBot)與當前頁面(嵌入端)的同步延遲超過10秒,導致連線中斷。", + "sign_time_invalid": "簽名時間格式無效,無法驗證嵌入方身分。", + "automation_tool_detected": "偵測到自動化工具存取,已阻止嵌入。", + "user_agent_mismatch": "簽名中的瀏覽器標識與當前請求不一致,已阻止嵌入。", + "timezone_mismatch": "簽名中的時區資訊與簽名時間不一致,已阻止嵌入。" }, "i18n_chat": { "record_id_in_mcp": "響應ID: "