147 lines
4.7 KiB
Python
147 lines
4.7 KiB
Python
"""代理 & 白名单配置路由"""
|
|
|
|
import re
|
|
import time
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..database import get_db
|
|
from ..models import User, ProxyConfig as ProxyConfigModel, AuditLog
|
|
from ..schemas import ProxyConfigOut, ProxyConfigUpdate, MessageResponse
|
|
from ..deps import require_permission
|
|
|
|
router = APIRouter(prefix="/api/proxy", tags=["代理与白名单"])
|
|
|
|
|
|
def _get_or_create(db: Session) -> ProxyConfigModel:
|
|
cfg = db.query(ProxyConfigModel).first()
|
|
if not cfg:
|
|
cfg = ProxyConfigModel()
|
|
db.add(cfg)
|
|
db.commit()
|
|
db.refresh(cfg)
|
|
return cfg
|
|
|
|
|
|
@router.get("", response_model=ProxyConfigOut)
|
|
def get_proxy_config(
|
|
db: Session = Depends(get_db),
|
|
_: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
return _get_or_create(db)
|
|
|
|
|
|
@router.put("", response_model=ProxyConfigOut)
|
|
def update_proxy_config(
|
|
req: ProxyConfigUpdate,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
cfg = _get_or_create(db)
|
|
cfg.enabled = req.enabled
|
|
cfg.api_url = req.api_url
|
|
cfg.http = req.http
|
|
cfg.https = req.https
|
|
cfg.whitelist_enabled = req.whitelist_enabled
|
|
cfg.whitelist_uid = req.whitelist_uid
|
|
cfg.whitelist_ukey = req.whitelist_ukey
|
|
db.commit()
|
|
db.refresh(cfg)
|
|
|
|
db.add(AuditLog(user_id=current.id, username=current.username,
|
|
action="proxy:update", target="proxy_config"))
|
|
db.commit()
|
|
return cfg
|
|
|
|
|
|
@router.post("/test")
|
|
def test_proxy(
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("proxy:manage")),
|
|
):
|
|
"""测试代理连通性。"""
|
|
import requests as req_lib
|
|
cfg = _get_or_create(db)
|
|
if not cfg.enabled:
|
|
return {"success": False, "message": "代理未启用"}
|
|
|
|
proxy_url = cfg.http or cfg.https
|
|
if cfg.api_url and not proxy_url:
|
|
try:
|
|
resp = req_lib.get(cfg.api_url, timeout=10)
|
|
match = re.search(r'(\d+\.\d+\.\d+\.\d+):(\d+)', resp.text)
|
|
if match:
|
|
proxy_url = f"http://{match.group(1)}:{match.group(2)}"
|
|
except Exception as e:
|
|
return {"success": False, "message": f"代理API请求失败: {e}"}
|
|
|
|
if not proxy_url:
|
|
return {"success": False, "message": "无可用代理地址"}
|
|
|
|
try:
|
|
resp = req_lib.get(
|
|
"https://qifu-api.baidubce.com/ip/local/geo/v1/district",
|
|
proxies={"http": proxy_url, "https": proxy_url},
|
|
timeout=(4, 6),
|
|
headers={"User-Agent": "Mozilla/5.0"},
|
|
)
|
|
resp.raise_for_status()
|
|
return {"success": True, "message": f"代理可用,响应: {resp.text[:100]}"}
|
|
except Exception as e:
|
|
return {"success": False, "message": f"代理验证失败: {e}"}
|
|
|
|
|
|
@router.post("/whitelist/test")
|
|
def test_whitelist(
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("whitelist:test")),
|
|
):
|
|
"""测试白名单连接并自动同步出口IP。"""
|
|
from douyu.whitelist import WhitelistManager, get_exit_ip_via_proxy
|
|
import requests as req_lib
|
|
|
|
cfg = _get_or_create(db)
|
|
if not cfg.whitelist_enabled:
|
|
return {"success": False, "message": "白名单未启用"}
|
|
if not cfg.whitelist_uid or not cfg.whitelist_ukey:
|
|
return {"success": False, "message": "未配置白名单UID/UKEY"}
|
|
|
|
manager = WhitelistManager(cfg.whitelist_uid, cfg.whitelist_ukey)
|
|
|
|
# 测试API连接
|
|
ok, msg = manager.test_connection()
|
|
if not ok:
|
|
return {"success": False, "message": msg}
|
|
|
|
# 获取出口IP
|
|
proxy_url = cfg.http or cfg.https
|
|
if cfg.api_url and not proxy_url:
|
|
try:
|
|
resp = req_lib.get(cfg.api_url, timeout=10)
|
|
match = re.search(r'(\d+\.\d+\.\d+\.\d+):(\d+)', resp.text)
|
|
if match:
|
|
proxy_url = f"http://{match.group(1)}:{match.group(2)}"
|
|
except Exception:
|
|
pass
|
|
|
|
exit_ip = None
|
|
if proxy_url:
|
|
exit_ip = get_exit_ip_via_proxy(proxy_url)
|
|
if not exit_ip:
|
|
try:
|
|
resp = req_lib.get("https://4.ipw.cn", timeout=6, headers={"User-Agent": "Mozilla/5.0"})
|
|
match = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', resp.text)
|
|
if match:
|
|
exit_ip = match.group(1)
|
|
except Exception:
|
|
pass
|
|
|
|
if not exit_ip:
|
|
return {"success": False, "message": "API连接正常但无法获取出口IP"}
|
|
|
|
# 同步白名单
|
|
sync_ok, sync_msg = manager.sync_ip(exit_ip)
|
|
if sync_ok:
|
|
return {"success": True, "message": f"出口IP {exit_ip} 已同步: {sync_msg}"}
|
|
return {"success": False, "message": f"同步失败: {sync_msg}"}
|