"""SSH-based Baota temporary login URL (tools.py).""" from __future__ import annotations import logging import re from urllib.parse import urlparse from server.domain.models import Server from server.infrastructure.ssh.asyncssh_pool import exec_ssh_command logger = logging.getLogger("nexus.btpanel.ssh") _BT_PANEL_TOOLS = "/www/server/panel/tools.py" _URL_RE = re.compile(r"^https?://\S+/login\?tmp_token=\S+$", re.IGNORECASE) SSH_TEMP_LOGIN_CMD = ( f"test -f {_BT_PANEL_TOOLS} && " f"cd /www/server/panel && python3 tools.py get_temp_login_ipv4 2>/dev/null | tail -1" ) DETECT_BT_CMD = "test -f /www/server/panel/class/common.py && echo BT_OK || echo BT_NO" async def detect_bt_panel_installed(server: Server) -> bool: result = await exec_ssh_command(server, DETECT_BT_CMD, timeout=20) if result.get("status") != "success": return False return "BT_OK" in (result.get("stdout") or "") def _rewrite_login_host(url: str, prefer_host: str) -> str: prefer_host = prefer_host.strip() if not prefer_host or not _URL_RE.match(url): return url parsed = urlparse(url) port = parsed.port or (443 if parsed.scheme == "https" else 80) return f"{parsed.scheme}://{prefer_host}:{port}{parsed.path}?{parsed.query}" async def ssh_temp_login_url(server: Server) -> str: result = await exec_ssh_command(server, SSH_TEMP_LOGIN_CMD, timeout=45) if result.get("status") != "success": raise RuntimeError(result.get("stderr") or result.get("stdout") or "SSH 执行失败") line = (result.get("stdout") or "").strip().splitlines()[-1].strip() if not _URL_RE.match(line): raise RuntimeError(f"未获得有效临时登录链接: {line[:120]}") return _rewrite_login_host(line, server.domain or "")