#!/usr/bin/env python3 """Dump Otantik Hub (id 15) SaaS + WG status. No private keys printed.""" from __future__ import annotations import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) import vps_ssh REMOTE = r""" python3 - <<'PY' import re, subprocess t = open("/var/www/wifi-otantik/config.php").read() def g(k): m = re.search(r"\$" + k + r"\s*=\s*['\"]([^'\"]+)", t) return m.group(1) if m else "" host = g("db_host") or "localhost" user = g("db_user") pw = g("db_pass") name = g("db_name") def mysql(sql): r = subprocess.run( ["mysql", "-h", host, "-u", user, f"-p{pw}", name, "-e", sql], capture_output=True, text=True, ) out = r.stdout if r.returncode: out += r.stderr.replace(pw, "***") return out print("==== ROUTER 15 / otantik-hub ====") print(mysql( "SELECT id,name,slug,owner_id,ip_address,username," "IF(password IS NULL OR password='', 'EMPTY', 'SET') AS pw," "ssid,ros_version,pppoe_interface,enabled,status " "FROM tbl_routers WHERE id=15 OR slug='otantik-hub'" )) print("==== PEER (no secrets) ====") print(mysql( "SELECT id,router_id,owner_id,wg_ip,status," "LEFT(public_key,16) AS pub_prefix, CHAR_LENGTH(public_key) AS pub_len," "CHAR_LENGTH(private_key) AS priv_len, last_seen " "FROM tbl_otantik_peers WHERE router_id=15 OR wg_ip LIKE '10.88.0.6%'" )) print("==== PUB FULL for compare ====") print(mysql("SELECT public_key FROM tbl_otantik_peers WHERE router_id=15")) PY echo "==== WG SHOW (filtered) ====" sudo -n /usr/local/sbin/otantik-wg show 2>/dev/null || sudo /usr/local/sbin/otantik-wg show echo "==== PING 10.88.0.6 ====" ping -c 3 -W 3 10.88.0.6 || true echo "==== API 8728 ====" timeout 5 bash -lc 'echo | nc -vz 10.88.0.6 8728' 2>&1 || true """ code, out = vps_ssh.run(REMOTE, timeout=60) print("code", code) # redact any accidental private-key-looking lines if a dump includes them for line in out.splitlines(): low = line.lower() if "private-key" in low or "private_key" in low and "priv_len" not in low: print("[redacted private]") continue print(line)