276 lines
11 KiB
Python
276 lines
11 KiB
Python
import os
|
|
import shutil
|
|
import re
|
|
import zipfile
|
|
import requests
|
|
from stuff.general import General
|
|
from tools.helper import bcolors, download_file, host, print_color, run, get_download_dir
|
|
|
|
class Magisk(General):
|
|
stable_json = "https://raw.githubusercontent.com/os-fork/HuskyDG-magisk-files/main/stable.json"
|
|
machine = host()
|
|
|
|
def __init__(self):
|
|
self.download_loc = get_download_dir()
|
|
self.dl_file_name = os.path.join(self.download_loc, "magisk.apk")
|
|
self.release_meta_file = os.path.join(self.download_loc, "magisk.version")
|
|
self.extract_to = os.path.join(self.download_loc, "magisk_unpack")
|
|
self.copy_dir = "./magisk"
|
|
self.magisk_dir = os.path.join(self.copy_dir, "vendor", "etc", "magisk")
|
|
self.rc_dir = os.path.join(self.copy_dir, "vendor", "etc", "init")
|
|
self.app_package = os.environ.get("REDROID_MAGISK_APP_PACKAGE", "io.github.huskydg.magisk")
|
|
self.custom_apk = os.environ.get("REDROID_MAGISK_APK", "").strip()
|
|
self.custom_url = os.environ.get("REDROID_MAGISK_URL", "").strip()
|
|
self.boot_complete_enabled = os.environ.get("REDROID_MAGISK_BOOT_COMPLETE", "0").strip().lower() in {
|
|
"1",
|
|
"true",
|
|
"yes",
|
|
"on",
|
|
}
|
|
self.preseed_sql = os.environ.get(
|
|
"REDROID_MAGISK_PRESEED_SQL",
|
|
"REPLACE INTO settings (key,value) VALUES "
|
|
"('root_access',3),('su_biometric',0),('multiuser_mode',0),('mnt_ns',1),"
|
|
"('denylist',0),('sulist',0),('zygisk',1); "
|
|
"REPLACE INTO policies (uid,policy,until,logging,notification) VALUES "
|
|
"(2000,2,0,0,0);",
|
|
).strip()
|
|
self.release_version = "unknown"
|
|
self.magisk_tmp = "/debug_ramdisk"
|
|
self.magisk_bootstrap = "magisk64" if self.machine[1] == 64 else "magisk32"
|
|
self.magisk_system_dir = "/vendor/etc/magisk"
|
|
boot_complete_component = ""
|
|
if self.boot_complete_enabled:
|
|
boot_complete_component = """
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --boot-complete""".format(
|
|
MAGISKTMP=self.magisk_tmp,
|
|
)
|
|
preseed_component = ""
|
|
if self.preseed_sql:
|
|
escaped_sql = self.preseed_sql.replace("\\", "\\\\").replace('"', '\\"')
|
|
preseed_component = """
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --sqlite "{PRESEED_SQL}" """.format(
|
|
MAGISKTMP=self.magisk_tmp,
|
|
PRESEED_SQL=escaped_sql,
|
|
)
|
|
self.bootanim_component = """
|
|
on post-fs-data
|
|
start logd
|
|
mount tmpfs tmpfs {MAGISKTMP} mode=1777
|
|
mkdir /data/adb 0700
|
|
mkdir /data/adb/magisk 0755
|
|
copy {MAGISKSYSTEMDIR}/busybox /data/adb/magisk/busybox
|
|
copy {MAGISKSYSTEMDIR}/magiskboot /data/adb/magisk/magiskboot
|
|
copy {MAGISKSYSTEMDIR}/magiskinit /data/adb/magisk/magiskinit
|
|
copy {MAGISKSYSTEMDIR}/magiskpolicy /data/adb/magisk/magiskpolicy
|
|
copy {MAGISKSYSTEMDIR}/util_functions.sh /data/adb/magisk/util_functions.sh
|
|
copy {MAGISKSYSTEMDIR}/boot_patch.sh /data/adb/magisk/boot_patch.sh
|
|
copy {MAGISKSYSTEMDIR}/addon.d.sh /data/adb/magisk/addon.d.sh
|
|
chmod 0755 /data/adb/magisk/busybox
|
|
chmod 0755 /data/adb/magisk/magiskboot
|
|
chmod 0755 /data/adb/magisk/magiskinit
|
|
chmod 0755 /data/adb/magisk/magiskpolicy
|
|
chmod 0644 /data/adb/magisk/util_functions.sh
|
|
chmod 0644 /data/adb/magisk/boot_patch.sh
|
|
chmod 0644 /data/adb/magisk/addon.d.sh
|
|
copy {MAGISKSYSTEMDIR}/magisk32 {MAGISKTMP}/magisk32
|
|
copy {MAGISKSYSTEMDIR}/magisk64 {MAGISKTMP}/magisk64
|
|
copy {MAGISKSYSTEMDIR}/magiskpolicy {MAGISKTMP}/magiskpolicy
|
|
copy {MAGISKSYSTEMDIR}/stub.apk {MAGISKTMP}/stub.apk
|
|
chmod 0755 {MAGISKTMP}/magisk32
|
|
chmod 0755 {MAGISKTMP}/magisk64
|
|
chmod 0755 {MAGISKTMP}/magiskpolicy
|
|
symlink {MAGISKTMP}/{magisk_bootstrap} {MAGISKTMP}/magisk
|
|
symlink {MAGISKTMP}/magisk {MAGISKTMP}/su
|
|
symlink {MAGISKTMP}/magisk {MAGISKTMP}/resetprop
|
|
symlink {MAGISKTMP}/magiskpolicy {MAGISKTMP}/supolicy
|
|
rm /vendor/bin/su
|
|
rm /vendor/bin/magisk
|
|
rm /vendor/bin/resetprop
|
|
rm /vendor/bin/magiskpolicy
|
|
symlink {MAGISKTMP}/magisk /vendor/bin/su
|
|
symlink {MAGISKTMP}/magisk /vendor/bin/magisk
|
|
symlink {MAGISKTMP}/magisk /vendor/bin/resetprop
|
|
symlink {MAGISKTMP}/magiskpolicy /vendor/bin/magiskpolicy
|
|
mkdir {MAGISKTMP}/.magisk 0711
|
|
mkdir {MAGISKTMP}/.magisk/device 0711
|
|
mkdir {MAGISKTMP}/.magisk/mirror 0755
|
|
mkdir {MAGISKTMP}/.magisk/block 0755
|
|
mkdir {MAGISKTMP}/.magisk/worker 0755
|
|
mkdir {MAGISKTMP}/.magisk/rootdir 0755
|
|
copy {MAGISKSYSTEMDIR}/config {MAGISKTMP}/.magisk/config
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --post-fs-data
|
|
|
|
on nonencrypted
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --service
|
|
|
|
on property:vold.decrypt=trigger_restart_framework
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --service
|
|
|
|
on property:sys.boot_completed=1
|
|
mkdir /data/adb/magisk 755
|
|
{PRESEED}
|
|
{BOOTCOMPLETE}
|
|
exec -- /system/bin/sh -c "if [ ! -e /data/data/{app_package} ] ; then pm install {MAGISKSYSTEMDIR}/magisk.apk ; fi"
|
|
|
|
on property:init.svc.zygote=restarting
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --zygote-restart
|
|
|
|
on property:init.svc.zygote=stopped
|
|
exec u:r:su:s0 root root -- {MAGISKTMP}/magisk --zygote-restart
|
|
""".format(
|
|
MAGISKSYSTEMDIR=self.magisk_system_dir,
|
|
MAGISKTMP=self.magisk_tmp,
|
|
PRESEED=preseed_component,
|
|
BOOTCOMPLETE=boot_complete_component,
|
|
magisk_bootstrap=self.magisk_bootstrap,
|
|
app_package=self.app_package,
|
|
)
|
|
|
|
def _cached_version(self):
|
|
if os.path.isfile(self.release_meta_file):
|
|
with open(self.release_meta_file, "r", encoding="utf-8") as meta_file:
|
|
return meta_file.read().strip()
|
|
return ""
|
|
|
|
def _write_version(self):
|
|
with open(self.release_meta_file, "w", encoding="utf-8") as meta_file:
|
|
meta_file.write(self.release_version)
|
|
|
|
def _validate_archive(self):
|
|
if not zipfile.is_zipfile(self.dl_file_name):
|
|
raise ValueError(
|
|
"Downloaded Magisk/Kitsune archive is not a valid APK/ZIP. "
|
|
"Set REDROID_MAGISK_APK to a local APK or REDROID_MAGISK_URL to a working direct APK URL."
|
|
)
|
|
|
|
def resolve_release(self):
|
|
print_color("Resolving Kitsune Mask stable release ...", bcolors.GREEN)
|
|
response = requests.get(self.stable_json, timeout=30)
|
|
response.raise_for_status()
|
|
payload = response.json()
|
|
magisk_info = payload["magisk"]
|
|
self.dl_link = magisk_info["link"]
|
|
self.release_version = magisk_info.get("version", "unknown")
|
|
|
|
def download(self):
|
|
if self.custom_apk:
|
|
self.release_version = "local:" + os.path.basename(self.custom_apk)
|
|
if (
|
|
os.path.isfile(self.dl_file_name)
|
|
and self._cached_version() == self.release_version
|
|
):
|
|
print_color(
|
|
"Using cached local Magisk/Kitsune APK {} ...".format(self.release_version),
|
|
bcolors.GREEN,
|
|
)
|
|
else:
|
|
print_color(
|
|
"Copying local Magisk/Kitsune APK {} ...".format(self.custom_apk),
|
|
bcolors.GREEN,
|
|
)
|
|
shutil.copyfile(self.custom_apk, self.dl_file_name)
|
|
self._write_version()
|
|
self._validate_archive()
|
|
return
|
|
|
|
if self.custom_url:
|
|
self.dl_link = self.custom_url
|
|
self.release_version = "url:" + os.path.basename(self.custom_url)
|
|
else:
|
|
self.resolve_release()
|
|
|
|
if (
|
|
os.path.isfile(self.dl_file_name)
|
|
and self._cached_version() == self.release_version
|
|
):
|
|
print_color(
|
|
"Using cached Kitsune Mask {} ...".format(self.release_version),
|
|
bcolors.GREEN,
|
|
)
|
|
self._validate_archive()
|
|
return
|
|
|
|
print_color(
|
|
"Downloading Kitsune Mask {} now .....".format(self.release_version),
|
|
bcolors.GREEN,
|
|
)
|
|
if os.path.isfile(self.dl_file_name):
|
|
os.remove(self.dl_file_name)
|
|
download_file(self.dl_link, self.dl_file_name)
|
|
self._validate_archive()
|
|
self._write_version()
|
|
|
|
def extract(self):
|
|
print_color("Extracting archive...", bcolors.GREEN)
|
|
if os.path.exists(self.extract_to):
|
|
shutil.rmtree(self.extract_to)
|
|
os.makedirs(self.extract_to, exist_ok=True)
|
|
with zipfile.ZipFile(self.dl_file_name) as zip_handle:
|
|
zip_handle.extractall(self.extract_to)
|
|
|
|
def copy(self):
|
|
if os.path.exists(self.copy_dir):
|
|
shutil.rmtree(self.copy_dir)
|
|
os.makedirs(self.magisk_dir, exist_ok=True)
|
|
os.makedirs(self.rc_dir, exist_ok=True)
|
|
os.chmod(os.path.join(self.copy_dir, "vendor"), 0o755)
|
|
os.chmod(os.path.join(self.copy_dir, "vendor", "etc"), 0o755)
|
|
os.chmod(self.magisk_dir, 0o755)
|
|
os.chmod(self.rc_dir, 0o755)
|
|
|
|
print_color("Copying magisk libs now ...", bcolors.GREEN)
|
|
|
|
arch_map = {
|
|
"x86": "x86",
|
|
"x86_64": "x86_64",
|
|
"arm": "armeabi-v7a",
|
|
"arm64": "arm64-v8a"
|
|
}
|
|
lib_dir = os.path.join(self.extract_to, "lib", arch_map[self.machine[0]])
|
|
for parent, dirnames, filenames in os.walk(lib_dir):
|
|
for filename in filenames:
|
|
o_path = os.path.join(lib_dir, filename)
|
|
filename = re.search(r'lib(.*)\.so', filename)
|
|
n_path = os.path.join(self.magisk_dir, filename.group(1))
|
|
shutil.copyfile(o_path, n_path)
|
|
os.chmod(n_path, 0o755)
|
|
|
|
if self.machine[1] == 64:
|
|
secondary_arch_map = {
|
|
"x86_64": "x86",
|
|
"arm64": "armeabi-v7a",
|
|
}
|
|
secondary_dir = os.path.join(
|
|
self.extract_to,
|
|
"lib",
|
|
secondary_arch_map[self.machine[0]],
|
|
)
|
|
magisk32_src = os.path.join(secondary_dir, "libmagisk32.so")
|
|
if os.path.exists(magisk32_src):
|
|
magisk32_dst = os.path.join(self.magisk_dir, "magisk32")
|
|
shutil.copyfile(magisk32_src, magisk32_dst)
|
|
os.chmod(magisk32_dst, 0o755)
|
|
|
|
assets_dir = os.path.join(self.extract_to, "assets")
|
|
for asset_name in ["util_functions.sh", "addon.d.sh", "boot_patch.sh", "stub.apk"]:
|
|
asset_src = os.path.join(assets_dir, asset_name)
|
|
if os.path.exists(asset_src):
|
|
asset_dst = os.path.join(self.magisk_dir, asset_name)
|
|
shutil.copyfile(asset_src, asset_dst)
|
|
os.chmod(asset_dst, 0o644)
|
|
|
|
config_path = os.path.join(self.magisk_dir, "config")
|
|
with open(config_path, "w", encoding="utf-8") as config_file:
|
|
config_file.write("SYSTEMMODE=true\nRECOVERYMODE=false\n")
|
|
os.chmod(config_path, 0o600)
|
|
|
|
magisk_apk_path = os.path.join(self.magisk_dir, "magisk.apk")
|
|
shutil.copyfile(self.dl_file_name, magisk_apk_path)
|
|
os.chmod(magisk_apk_path, 0o644)
|
|
|
|
magisk_rc_path = os.path.join(self.rc_dir, "magisk.rc")
|
|
with open(magisk_rc_path, "w", encoding="utf-8") as initfile:
|
|
initfile.write(self.bootanim_component)
|
|
os.chmod(magisk_rc_path, 0o644)
|