chore: python package

This commit is contained in:
zx
2024-09-03 19:46:22 -04:00
parent d7f38047be
commit 800bb8d5bf
11 changed files with 90 additions and 59 deletions

152
cyan/tbhutils.py Normal file
View File

@@ -0,0 +1,152 @@
import os
import sys
import shutil
import zipfile
import platform
import plistlib
import subprocess
from glob import glob
from argparse import Namespace
from importlib import resources # type: ignore
from typing import Optional, Any
from tempfile import TemporaryDirectory
def validate_inputs(args: Namespace) -> Optional[str]:
if not (
args.i.endswith(".ipa")
or args.i.endswith(".app")
):
return "the input file must be an ipa/app"
if not os.path.exists(args.i):
return f"{args.i} does not exist"
if os.path.exists(args.o):
try:
overwrite = input(
f"[<] {args.o} already exists, overwrite it? [Y/n] "
if args.output is not None
else "[<] no output was specified. overwrite the input? [Y/n] "
).strip().lower()
except KeyboardInterrupt:
sys.exit("[>] bye!")
if overwrite not in ("y", "yes", ""):
print("[>] quitting.")
sys.exit(0)
if args.f is not None:
# dictionary ensures unique names
args.f = {os.path.basename(f): os.path.normpath(f) for f in args.f}
nonexistent = [f for f in args.f.values() if not os.path.exists(f)]
if len(nonexistent) != 0:
print("[!] please ensure the following file(s) exist:")
for ne in nonexistent:
print(f"[?] - {ne}")
sys.exit(1)
def get_app(path: str, tmpdir: str, is_ipa: bool) -> tuple[str, str]:
payload = f"{tmpdir}/Payload"
if is_ipa:
print("[*] extracting ipa..")
try:
with zipfile.ZipFile(path) as ipa:
names = ipa.namelist()
if not any(name.startswith("Payload/") for name in names):
raise KeyError
elif not any(name.endswith(".app/Info.plist") for name in names):
sys.exit("[!] no Info.plist, invalid app")
ipa.extractall(tmpdir)
app = glob(f"{payload}/*.app")[0]
plist = f"{app}/Info.plist"
except (KeyError, IndexError):
sys.exit("[!] couldn't find either Payload or app folder, invalid ipa")
except zipfile.BadZipFile:
sys.exit(f"[!] {path} is not a zipfile (ipa)")
print("[*] extracted ipa")
else:
if not os.path.isfile((plist := f"{path}/Info.plist")):
sys.exit("[!] no Info.plist, invalid app")
print("[*] copying app..")
shutil.copytree(path, (app := f"{payload}/{os.path.basename(path)}"))
print("[*] copied app")
return app, plist
def get_tools_dir() -> tuple[str, str]:
mach = platform.machine()
system = platform.system()
if "iPhone" in mach or "iPad" in mach:
mach = "arm64"
with resources.files() as files: # type: ignore
return (
str(files), # type: ignore
str(files / "tools" / system / mach) # type: ignore
)
def get_plist(path: str) -> dict[str, Any]:
try:
with open(path, "rb") as f:
return plistlib.load(f)
except Exception:
sys.exit(f"[!] couldn't read {path}")
def delete_if_exists(path: str, bn: str) -> bool:
is_file = os.path.isfile(path)
try:
if is_file:
os.remove(path)
else:
shutil.rmtree(path)
print(f"[?] {bn} already existed, replacing")
return True
except FileNotFoundError:
return False
def extract_deb(deb: str, tweaks: dict[str, str], tmpdir: str) -> None:
with TemporaryDirectory(prefix=tmpdir + "/", delete=False) as t2:
if platform.system() == "Linux":
tool = ["ar", "-x", deb, f"--output={t2}"]
else:
tool = ["tar", "-xf", deb, f"--directory={t2}"]
try:
subprocess.run(tool, check=True)
except Exception:
sys.exit(f"[!] couldn't extract {os.path.basename(deb)}")
# it's not always "data.tar.gz"
data_tar = glob(f"{t2}/data.*")[0]
subprocess.run(["tar", "-xf", data_tar, f"--directory={t2}"])
for hi in sum((
glob(f"{t2}/**/*.dylib", recursive=True),
glob(f"{t2}/**/*.bundle", recursive=True),
glob(f"{t2}/**/*.appex", recursive=True),
glob(f"{t2}/**/*.framework", recursive=True)
), []): # type: ignore
if os.path.islink(hi):
continue # symlinks are broken iirc
tweaks[os.path.basename(hi)] = hi
print(f"[*] extracted {os.path.basename(deb)}")
del tweaks[deb]