This commit is contained in:
2026-05-07 12:30:51 -04:00
parent 2ed785e214
commit 59d8db92ca
32 changed files with 1796 additions and 290 deletions
+68 -29
View File
@@ -5,14 +5,25 @@ import subprocess
import time
import re
import os
from typing import Any, Dict, List
import auth_utils
import hashlib
from requests.exceptions import HTTPError
from datetime import datetime
from services import vpn_runtime
from services.vpn_runtime import VPNRuntimeError
requests.packages.urllib3.disable_warnings()
VPN_CONFIG_NAMES = ["Triton", "Star", "Bluebonnet", "Lonestar", "Production", "US-Support", "EU-Support"]
_VPN_NAMES_ENV = os.getenv(
"VPN_CONFIG_NAMES",
"Triton,Star,Bluebonnet,Lonestar,Production,US-Support,EU-Support",
)
VPN_CONFIG_NAMES = [name.strip() for name in _VPN_NAMES_ENV.split(",") if name.strip()]
def _format_host_for_https(host: str) -> str:
return f"[{host}]" if ":" in host and not host.startswith("[") else host
SERIAL_PASSWORDS = {
"3M1D2211Z3": "EP5G!f15878b4af20", "3M1D10146B": "EP5G!076689528baf",
@@ -207,38 +218,25 @@ def set_vpn_endpoint(host_ip, region):
return {"status": "success", "message": f"VPN endpoint switched to {region} ({new_ip})."}
def get_active_vpn():
for name in VPN_CONFIG_NAMES:
for pattern in ["openvpn-client@{name}.service", "openvpn@{name}.service"]:
try:
service_name = pattern.format(name=name)
cmd = ["/usr/bin/sudo", "/usr/bin/systemctl", "is-active", service_name]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.stdout.strip() == "active":
return name
except FileNotFoundError:
continue
return None
return vpn_runtime.get_active_vpn()
def toggle_vpn_connection(vpn_name, turn_on):
active_vpn = get_active_vpn()
if active_vpn:
subprocess.run(["/usr/bin/sudo", "/usr/bin/systemctl", "stop", f"openvpn-client@{active_vpn}.service"])
subprocess.run(["/usr/bin/sudo", "/usr/bin/systemctl", "stop", f"openvpn@{active_vpn}.service"])
vpn_name = (vpn_name or "").strip()
if turn_on and vpn_name and VPN_CONFIG_NAMES and vpn_name not in VPN_CONFIG_NAMES:
raise ValueError(f"Unsupported VPN '{vpn_name}'")
if turn_on:
try:
service_name = f"openvpn-client@{vpn_name}.service"
cmd = ["/usr/bin/sudo", "/usr/bin/systemctl", "start", service_name]
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError:
service_name = f"openvpn@{vpn_name}.service"
cmd = ["/usr/bin/sudo", "/usr/bin/systemctl", "start", service_name]
subprocess.run(cmd, check=True)
time.sleep(4)
if get_active_vpn() != vpn_name:
raise Exception(f"Connection failed for {vpn_name}. Check OpenVPN logs for details.")
try:
if turn_on:
if not vpn_name:
raise ValueError("vpn_name is required when turning on a VPN")
vpn_runtime.start_vpn(vpn_name)
else:
vpn_runtime.stop_active_vpn()
except VPNRuntimeError as exc:
raise Exception(str(exc)) from exc
return get_active_vpn()
return vpn_runtime.get_active_vpn()
def get_full_network_config(base_url, token, session):
network_url = f"{base_url}/portal/api/1/network"
@@ -372,6 +370,47 @@ def get_system_browser_data():
return list(vpn_clients.values())
def _extract_subscriber_list(payload: Any) -> List[Dict[str, Any]]:
if isinstance(payload, list):
return payload
if not isinstance(payload, dict):
return []
for key in ("subscribers", "items", "data", "results"):
value = payload.get(key)
if isinstance(value, list):
return value
return []
def list_network_clients(host_ip: str, limit: int = 500, page_size: int = 200, timeout: float = 15.0) -> List[Dict[str, Any]]:
"""Fetch SUPI/network client data from the target ComboCore host."""
if limit <= 0:
raise ValueError("limit must be positive")
token = auth_utils.authenticate(host_ip)
formatted_host = _format_host_for_https(host_ip)
base_url = f"https://{formatted_host}/core/udm/api/1/status/supis/"
headers = {"Authorization": f"Bearer {token}"}
collected: List[Dict[str, Any]] = []
offset = 0
while len(collected) < limit:
batch_size = min(page_size, limit - len(collected))
params = {"limit": batch_size, "offset": offset}
resp = requests.get(base_url, headers=headers, params=params, verify=False, timeout=timeout)
resp.raise_for_status()
data = resp.json()
items = _extract_subscriber_list(data)
if not isinstance(items, list):
raise RuntimeError("Unexpected subscriber payload format")
collected.extend(items)
if len(items) < batch_size:
break
offset = data.get("next_offset", offset + batch_size) if isinstance(data, dict) else offset + batch_size
return collected[:limit]
# ------- System ID Data Begin ---------
def _make_host_api_get_request(host_ip, token, endpoint):