fix: prevent Gitea token corruption from masked config values, add real connection test
This commit is contained in:
@@ -64,6 +64,11 @@ async def get_config(
|
||||
return result
|
||||
|
||||
|
||||
def _is_masked(key: str, value: str) -> bool:
|
||||
"""Check if a value looks like a masked sensitive field (contains asterisks)."""
|
||||
return any(s in key.lower() for s in _SENSITIVE_KEYS) and '*' in value
|
||||
|
||||
|
||||
@router.put("")
|
||||
async def update_config(
|
||||
body: ConfigUpdate,
|
||||
@@ -72,6 +77,9 @@ async def update_config(
|
||||
if body.section not in _ALLOWED_SECTIONS:
|
||||
raise HTTPException(403, f"不允许修改配置节: {body.section}")
|
||||
|
||||
if _is_masked(body.key, body.value):
|
||||
raise HTTPException(400, "敏感字段不能直接提交掩码值,请先清除输入框再输入真实值")
|
||||
|
||||
cfg = _get_config()
|
||||
try:
|
||||
cfg.update(body.section, body.key, body.value)
|
||||
@@ -88,11 +96,19 @@ async def bulk_update_config(
|
||||
):
|
||||
cfg = _get_config()
|
||||
updated = []
|
||||
skipped = []
|
||||
for item in body.updates:
|
||||
if item.section not in _ALLOWED_SECTIONS:
|
||||
continue
|
||||
# Skip masked sensitive values to prevent destroying real credentials
|
||||
if _is_masked(item.key, item.value):
|
||||
skipped.append(f"[{item.section}] {item.key}")
|
||||
continue
|
||||
cfg.update(item.section, item.key, item.value)
|
||||
updated.append(f"[{item.section}] {item.key}")
|
||||
|
||||
cfg.save_config()
|
||||
return {"message": f"已更新 {len(updated)} 项", "updated": updated}
|
||||
msg = f"已更新 {len(updated)} 项"
|
||||
if skipped:
|
||||
msg += f",跳过 {len(skipped)} 项掩码值"
|
||||
return {"message": msg, "updated": updated, "skipped": skipped}
|
||||
|
||||
@@ -78,6 +78,7 @@ async def sync_status(
|
||||
):
|
||||
try:
|
||||
from app.config.settings import ConfigManager
|
||||
import httpx as _httpx
|
||||
cfg = ConfigManager()
|
||||
base_url = cfg.get("Gitea", "base_url", fallback="").strip()
|
||||
owner = cfg.get("Gitea", "owner", fallback="").strip()
|
||||
@@ -85,6 +86,22 @@ async def sync_status(
|
||||
token = cfg.get("Gitea", "token", fallback="").strip()
|
||||
enabled = bool(base_url and owner and repo and token)
|
||||
repo_url = f"{base_url}/{owner}/{repo}" if enabled else ""
|
||||
return {"enabled": enabled, "repo_url": repo_url}
|
||||
except Exception:
|
||||
return {"enabled": False, "repo_url": ""}
|
||||
|
||||
connected = False
|
||||
error = ""
|
||||
if enabled:
|
||||
try:
|
||||
async with _httpx.AsyncClient(timeout=10) as client:
|
||||
resp = await client.get(
|
||||
f"{base_url}/api/v1/repos/{owner}/{repo}",
|
||||
headers={"Authorization": f"token {token}"},
|
||||
)
|
||||
connected = resp.status_code == 200
|
||||
if not connected:
|
||||
error = f"Gitea 返回 {resp.status_code}"
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
|
||||
return {"enabled": enabled, "connected": connected, "repo_url": repo_url, "error": error}
|
||||
except Exception as e:
|
||||
return {"enabled": False, "connected": False, "repo_url": "", "error": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user