Files
Nexus/server/utils/http_errors_zh.py
T
Nexus Agent a842af2405 fix(auth): use Chinese fallbacks and map reason codes to user messages
Stop exposing raw reason codes like admin_not_found in TOTP setup errors;
auth routes and JWT guard now use Chinese literals with auth_failure_detail.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 08:44:51 +08:00

117 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Translate HTTPException detail strings to Chinese for admin-facing API responses."""
from __future__ import annotations
import re
from typing import Any
# Exact English literals from server/api (and shared services)
_DETAIL_EXACT: dict[str, str] = {
"Not found": "不存在",
"Server not found": "服务器不存在",
"Platform not found": "平台不存在",
"Node not found": "节点不存在",
"Admin not found": "管理员不存在",
"Setting not found": "设置项不存在",
"API_KEY not found": "API_KEY 不存在",
"Schedule not found": "调度任务不存在",
"Preset not found": "凭据预设不存在",
"SSH key preset not found": "SSH 密钥预设不存在",
"telegram_bot_token not found": "telegram_bot_token 不存在",
"Retry job not found": "重试任务不存在",
"Credential not found": "凭据不存在",
"Execution not found": "执行记录不存在",
"Script not found": "脚本不存在",
"Login failed": "登录失败",
"Missing refresh token": "缺少刷新令牌",
"Invalid refresh token": "刷新令牌无效",
"Missing Authorization header": "缺少 Authorization 请求头",
"Invalid or expired token": "令牌无效或已过期",
"Can only setup TOTP for yourself": "只能为自己设置 TOTP",
"Can only enable TOTP for yourself": "只能为自己启用 TOTP",
"Can only disable TOTP for yourself": "只能为自己禁用 TOTP",
"Setup failed": "设置失败",
"Enable failed": "启用失败",
"Disable failed": "禁用失败",
"Server has no domain configured": "服务器未配置域名",
"Missing API key": "缺少 API Key",
"Invalid API key for this server": "该服务器的 API Key 无效",
"Invalid or expired job": "任务无效或已过期",
"new_path required for rename": "重命名需要指定 new_path",
"Invalid operation": "无效操作",
"server_id required": "server_id 必填",
"Too many script callback requests": "脚本回调请求过于频繁",
}
# AuthService ``reason`` codes → user-facing Chinese (when ``message`` absent)
_AUTH_REASON_ZH: dict[str, str] = {
"admin_not_found": "管理员不存在",
"no_secret": "请先完成 TOTP 设置",
"invalid_totp": "TOTP 验证码错误",
"invalid_password": "当前密码错误",
"totp_required": "需要 TOTP 验证码",
"invalid_token": "令牌无效或已过期",
"invalid_credentials": "用户名或密码错误",
"account_locked": "登录尝试过多,请 15 分钟后重试",
"account_disabled": "账户已被禁用",
"ip_blocked": "拒绝访问",
"service_unavailable": "认证服务暂不可用,请稍后重试",
}
_DETAIL_PATTERNS: list[tuple[re.Pattern[str], str]] = [
(
re.compile(r"^Command failed \(exit (\d+)\)$"),
r"命令失败(退出码 \1",
),
(
re.compile(
r"^Setting '([^']+)' is immutable and cannot be modified via API$"
),
r"设置项「\1」不可通过 API 修改",
),
]
def _looks_chinese(text: str) -> bool:
return any("\u4e00" <= ch <= "\u9fff" for ch in text)
def translate_http_detail_str(msg: str) -> str:
"""Return Chinese detail when a known translation exists."""
if not msg or _looks_chinese(msg):
return msg
if msg in _DETAIL_EXACT:
return _DETAIL_EXACT[msg]
for pattern, repl in _DETAIL_PATTERNS:
if pattern.fullmatch(msg):
return pattern.sub(repl, msg)
return msg
def auth_failure_detail(result: dict[str, Any], *, fallback: str = "操作失败") -> str:
"""Map AuthService failure dict to Chinese ``HTTPException.detail``."""
msg = result.get("message")
if isinstance(msg, str) and msg.strip():
return translate_http_detail_str(msg)
reason = str(result.get("reason") or "")
if reason in _AUTH_REASON_ZH:
return _AUTH_REASON_ZH[reason]
return fallback if _looks_chinese(fallback) else translate_http_detail_str(fallback)
def translate_http_detail(detail: Any) -> Any:
"""Translate ``HTTPException.detail`` (str | list | dict) for JSON responses."""
if isinstance(detail, str):
return translate_http_detail_str(detail)
if isinstance(detail, list):
return [translate_http_detail(item) for item in detail]
if isinstance(detail, dict):
out: dict[Any, Any] = {}
for key, value in detail.items():
if key in ("msg", "message") and isinstance(value, str):
out[key] = translate_http_detail_str(value)
else:
out[key] = value
return out
return detail