Files
HadTavern/agentui/config.py

199 lines
7.2 KiB
Python
Raw Permalink 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.

from typing import Dict, Optional, Union
from pathlib import Path
from urllib.parse import quote
import os
def _parse_proxy_line(line: str) -> Optional[str]:
# Формат: scheme:ip:port[:login[:pass]]
# Примеры:
# socks5:127.0.0.1:9050
# socks5:127.0.0.1:9050:user:pass
# http:127.0.0.1:8888
parts = [p.strip() for p in line.strip().split(":")]
if len(parts) < 3:
return None
scheme, host, port = parts[0], parts[1], parts[2]
user = parts[3] if len(parts) >= 4 and parts[3] else None
password = parts[4] if len(parts) >= 5 and parts[4] else None
auth = ""
if user:
auth = quote(user)
if password:
auth += f":{quote(password)}"
auth += "@"
# Исправление для socks5: httpx ожидает схему socks5:// (не socks://)
if scheme == "socks":
scheme = "socks5"
# Явно проверяем протокол, чтобы был http://, https:// или socks5://
if not scheme.startswith(("http", "socks")):
scheme = "http"
return f"{scheme}://{auth}{host}:{port}"
def _read_proxy_from_file() -> Optional[str]:
file_path = Path("proxy.txt")
if not file_path.exists():
return None
try:
for raw in file_path.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
# поддержим дополнительные ключи вида key=value в этом же файле (разберём ниже)
if "=" in line:
continue
url = _parse_proxy_line(line)
if url:
return url
except Exception:
return None
return None
def build_httpx_proxies() -> Optional[Dict[str, str]]:
# Читаем только из proxy.txt (без переменных окружения)
url = _read_proxy_from_file()
if not url:
return None
# Для httpx корректнее указывать схемы явно
return {
"http://": url,
"https://": url,
}
def _read_kv_from_proxy_file() -> Dict[str, str]:
"""
Поддержка дополнительных опций в proxy.txt:
ca=/полный/путь/к/burp-ca.pem
verify=false # отключить проверку сертификатов (для отладки)
"""
out: Dict[str, str] = {}
p = Path("proxy.txt")
if not p.exists():
return out
try:
for raw in p.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
continue
k, v = line.split("=", 1)
out[k.strip().lower()] = v.strip()
except Exception:
return out
return out
def _read_second_bare_flag_from_proxy() -> Optional[bool]:
"""
Читает «вторую голую строку» после URL в proxy.txt и интерпретирует как флаг verify:
true/1/yes/on -> True
false/0/no/off -> False
Возвращает None, если строка отсутствует или не распознана.
"""
try:
p = Path("proxy.txt")
if not p.exists():
return None
lines = [ln.strip() for ln in p.read_text(encoding="utf-8").splitlines()]
# найдём первую «URL» строку (без '=' и не пустую/коммент)
idx_url = -1
for i, ln in enumerate(lines):
if not ln or ln.startswith("#") or "=" in ln:
continue
idx_url = i
break
if idx_url >= 0:
# ищем следующую «голую» строку
for j in range(idx_url + 1, len(lines)):
ln = lines[j].strip()
if not ln or ln.startswith("#") or "=" in ln:
continue
low = ln.lower()
if low in ("1", "true", "yes", "on"):
return True
if low in ("0", "false", "no", "off"):
return False
# если это не похожее на флаг — считаем отсутствующим
break
except Exception:
return None
return None
def get_tls_verify() -> Union[bool, str]:
"""
Возвращает значение для параметра httpx.AsyncClient(verify=...):
- путь к PEM-бандлу (строка), если нашли ca=... или файл proxy-ca.pem в корне
- False, если verify=false/insecure=1/AGENTUI_VERIFY=false
- True по умолчанию
- Новое: можно задать флаг второй «голой» строкой в proxy.txt (после URL прокси):
пример:
http:127.0.0.1:8888
false
или
http:127.0.0.1:8888
true
"""
# 1) Переменные окружения имеют приоритет
env_verify = os.getenv("AGENTUI_VERIFY")
if env_verify is not None and env_verify.strip().lower() in ("0", "false", "no", "off"):
return False
env_ca = os.getenv("AGENTUI_CA")
if env_ca:
path = Path(env_ca).expanduser()
if path.exists():
return str(path)
# 2) proxy.txt ключи
kv = _read_kv_from_proxy_file()
if kv.get("verify", "").lower() in ("0", "false", "no", "off"):
return False
if "ca" in kv:
path = Path(kv["ca"]).expanduser()
if path.exists():
return str(path)
# 2.1) Дополнительно: поддержка второй строки без ключа — true/false
second = _read_second_bare_flag_from_proxy()
if second is True:
return True
if second is False:
return False
# 3) Файл по умолчанию в корне проекта
default_ca = Path("proxy-ca.pem")
if default_ca.exists():
return str(default_ca)
# 4) По умолчанию строгая проверка
return True
def is_verify_explicit() -> bool:
"""
Возвращает True, если пользователь ЯВНО задал политику проверки TLS,
чтобы клиент не переопределял её значением по умолчанию.
Учитываются:
- переменные окружения: AGENTUI_VERIFY, AGENTUI_CA
- ключи в proxy.txt: verify=..., ca=...
- файл proxy-ca.pem в корне проекта
- Новое: «вторая голая строка» после URL в proxy.txt со значением true/false
"""
if os.getenv("AGENTUI_VERIFY") is not None:
return True
if os.getenv("AGENTUI_CA"):
return True
kv = _read_kv_from_proxy_file()
if "verify" in kv or "ca" in kv:
return True
# Вторая «голая» строка как явный флаг
second = _read_second_bare_flag_from_proxy()
if second is not None:
return True
if Path("proxy-ca.pem").exists():
return True
return False