commit
This commit is contained in:
+68
-29
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user