perf: Internationalization (i18n) for In‑line Error Prompts

This commit is contained in:
fit2cloud-chenyw
2026-09-09 11:07:36 +08:00
committed by fit2cloud-chenyw
parent 4ee923c968
commit 900eb2d28e
5 changed files with 64 additions and 15 deletions
+20 -11
View File
@@ -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('/')
+11 -1
View File
@@ -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: "
+11 -1
View File
@@ -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: "
+11 -1
View File
@@ -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: "
+11 -1
View File
@@ -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: "