Skip to content

Commit 7662510

Browse files
committed
fix updater
1 parent 57ac74c commit 7662510

1 file changed

Lines changed: 58 additions & 8 deletions

File tree

UXTU4Linux/Assets/Modules/updater.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import hashlib
12
import json
23
import os
34
import shutil
@@ -14,7 +15,14 @@
1415
from .service import restart_service, service_running
1516

1617
_STABLE_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/latest/download/UXTU4Linux.zip"
17-
_BETA_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/download/U4L-Beta/UXTU4Linux.zip"
18+
_BETA_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/download/U4L-Beta/UXTU4Linux.zip"
19+
_STABLE_SHA256_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/latest/download/UXTU4Linux.zip.sha256"
20+
_BETA_SHA256_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/download/U4L-Beta/UXTU4Linux.zip.sha256"
21+
22+
_SHA256_URL: dict[str, str] = {
23+
_STABLE_URL: _STABLE_SHA256_URL,
24+
_BETA_URL: _BETA_SHA256_URL,
25+
}
1826

1927

2028
def _ver_tuple(v: str) -> tuple:
@@ -27,12 +35,29 @@ def _ver_tuple(v: str) -> tuple:
2735
return (0,)
2836

2937

30-
def _release_url(url: str) -> str:
38+
def _get_release_tag(url: str) -> str:
3139
return url.rstrip("/").split("/")[-1]
3240

3341

42+
def _sha256_file(path: str) -> str:
43+
h = hashlib.sha256()
44+
with open(path, "rb") as f:
45+
for chunk in iter(lambda: f.read(1024 * 1024), b""):
46+
h.update(chunk)
47+
return h.hexdigest()
48+
49+
50+
def _fetch_expected_sha256(sha_url: str) -> str:
51+
with urllib.request.urlopen(sha_url, timeout=10) as resp:
52+
raw = resp.read().decode("utf-8", errors="replace").strip()
53+
expected = raw.split()[0].lower()
54+
if len(expected) != 64 or not all(c in "0123456789abcdef" for c in expected):
55+
raise RuntimeError(f"Invalid checksum format from {sha_url}")
56+
return expected
57+
58+
3459
def get_latest_version() -> str:
35-
tag = _release_url(urllib.request.urlopen(cfg.LATEST_VER_URL, timeout=5).geturl())
60+
tag = _get_release_tag(urllib.request.urlopen(cfg.LATEST_VER_URL, timeout=5).geturl())
3661
if not tag or not tag.lstrip("v")[:1].isdigit():
3762
raise ValueError(f"Unexpected version tag: {tag!r}")
3863
return tag
@@ -44,7 +69,7 @@ def get_changelog() -> str:
4469
return data.get("body", "No changelog available.")
4570

4671

47-
def get_beta_commit() -> str | None:
72+
def get_beta_tag_sha() -> str | None:
4873
req = urllib.request.Request(
4974
"https://api.github.com/repos/HorizonUnix/UXTU4Linux/git/ref/tags/U4L-Beta",
5075
headers={"Accept": "application/vnd.github+json"},
@@ -54,11 +79,15 @@ def get_beta_commit() -> str | None:
5479
return sha[:7] if sha else None
5580

5681

82+
def get_beta_commit() -> str | None:
83+
return get_beta_tag_sha()
84+
85+
5786
def _do_update(url: str = _STABLE_URL) -> None:
5887

5988
module_file = Path(__file__).resolve()
60-
assets_dir = str(module_file.parent.parent)
61-
src_dir = str(module_file.parent.parent.parent)
89+
assets_dir = str(module_file.parent.parent)
90+
src_dir = str(module_file.parent.parent.parent)
6291
install_dir = str(module_file.parent.parent.parent.parent)
6392

6493
zip_path = os.path.join(install_dir, "UXTU4Linux.zip")
@@ -69,7 +98,15 @@ def _do_update(url: str = _STABLE_URL) -> None:
6998
presets_src = os.path.join(assets_dir, "custom.json")
7099

71100
def _sudo(*args: str) -> int:
72-
return subprocess.run(["sudo", *args]).returncode
101+
result = subprocess.run(["sudo", *args], capture_output=True, text=True)
102+
if result.returncode != 0:
103+
cmd = " ".join(["sudo", *args])
104+
print(f" Command failed ({result.returncode}): {cmd}")
105+
if result.stderr and result.stderr.strip():
106+
print(f" stderr: {result.stderr.strip()}")
107+
if result.stdout and result.stdout.strip():
108+
print(f" stdout: {result.stdout.strip()}")
109+
return result.returncode
73110

74111
try:
75112
if os.path.exists(config_src):
@@ -80,6 +117,19 @@ def _sudo(*args: str) -> int:
80117
print(" Downloading update...")
81118
urllib.request.urlretrieve(url, zip_path)
82119

120+
sha_url = _SHA256_URL.get(url)
121+
if sha_url:
122+
try:
123+
print(" Verifying integrity...")
124+
expected = _fetch_expected_sha256(sha_url)
125+
actual = _sha256_file(zip_path)
126+
if actual != expected:
127+
raise RuntimeError(
128+
f"Integrity check failed (expected {expected}, got {actual})."
129+
)
130+
except urllib.error.URLError:
131+
print(" Warning: checksum file not available — skipping integrity check.")
132+
83133
print(" Extracting...")
84134
with zipfile.ZipFile(zip_path, "r") as zf:
85135
zf.extractall(new_folder)
@@ -200,4 +250,4 @@ def check_updates() -> None:
200250
"It may be unstable and is intended for testing only."
201251
)
202252
if not confirm("Continue?", subtitle=subtitle):
203-
sys.exit("Quitting.")
253+
sys.exit("Quitting.")

0 commit comments

Comments
 (0)