mirror of
https://github.com/Realmzer/MySign-Repo.git
synced 2026-04-25 15:32:53 +00:00
add some python stuff
This commit is contained in:
parent
ae3f5b71af
commit
ee545b6092
7 changed files with 201 additions and 0 deletions
105
generate_json.py
Normal file
105
generate_json.py
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
from github import Github
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import pandas as pd
|
||||||
|
from get_bundle_id import get_single_bundle_id
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
REPO_NAME = "Realmzer/MySign-Repo"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-t", "--token", help="Github token")
|
||||||
|
args = parser.parse_args()
|
||||||
|
token = args.token
|
||||||
|
|
||||||
|
out_file = "apps-repo.json"
|
||||||
|
|
||||||
|
with open(out_file, "r") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
if os.path.isfile("bundleId.csv"):
|
||||||
|
df = pd.read_csv("bundleId.csv")
|
||||||
|
else:
|
||||||
|
df = pd.DataFrame(columns=["name", "bundleId", "genre"])
|
||||||
|
|
||||||
|
# clear apps
|
||||||
|
data["apps"] = []
|
||||||
|
|
||||||
|
g = Github(token)
|
||||||
|
repo = g.get_repo(REPO_NAME)
|
||||||
|
releases = repo.get_releases()
|
||||||
|
|
||||||
|
for release in releases:
|
||||||
|
for asset in release.get_assets():
|
||||||
|
if (spl := asset.name.split("."))[-1] not in ("ipa", "dylib", "deb"):
|
||||||
|
continue
|
||||||
|
IS_IPA = spl[-1] == "ipa"
|
||||||
|
name = ".".join(spl[:-1])
|
||||||
|
date = asset.created_at.strftime("%Y-%m-%d")
|
||||||
|
full_date = asset.created_at.strftime("%Y%m%d%H%M%S")
|
||||||
|
try:
|
||||||
|
app_name, version, tweaks = name.split("_", 2)
|
||||||
|
tweaks, _ = tweaks.split("@", 1)
|
||||||
|
if tweaks:
|
||||||
|
tweaks = f"Injected with {tweaks[:-1].replace("_", " ")}"
|
||||||
|
except Exception:
|
||||||
|
app_name = name
|
||||||
|
version = "Unknown"
|
||||||
|
tweaks = None
|
||||||
|
|
||||||
|
if IS_IPA:
|
||||||
|
if app_name in df.name.values:
|
||||||
|
info = {"bundle": df[df.name == app_name].bundleId.values[0], "genre": df[df.name == app_name].genre.values[0]}
|
||||||
|
else:
|
||||||
|
info: dict = get_single_bundle_id(asset.browser_download_url)
|
||||||
|
|
||||||
|
if "error" in info:
|
||||||
|
print(f"[*] error detected in '{name}', deleting")
|
||||||
|
asset.delete_asset()
|
||||||
|
continue
|
||||||
|
|
||||||
|
df = pd.concat([df, pd.DataFrame(
|
||||||
|
{"name": [app_name], "bundleId": [info["bundle"]], "genre": [info["genre"]]})], ignore_index=True)
|
||||||
|
|
||||||
|
data["apps"].append({
|
||||||
|
"name": app_name,
|
||||||
|
"type": int(info["genre"]),
|
||||||
|
"bundleID": str(info["bundle"]),
|
||||||
|
"bundleIdentifier": str(info["bundle"]),
|
||||||
|
"version": version,
|
||||||
|
"versionDate": date,
|
||||||
|
"fullDate": full_date,
|
||||||
|
"size": int(asset.size),
|
||||||
|
"down": asset.browser_download_url,
|
||||||
|
"downloadURL": asset.browser_download_url,
|
||||||
|
"developerName": "",
|
||||||
|
"localizedDescription": tweaks,
|
||||||
|
"icon": f"https://raw.githubusercontent.com/{REPO_NAME}/main/icons/{info["bundle"]}.png",
|
||||||
|
"iconURL": f"https://raw.githubusercontent.com/{REPO_NAME}/main/icons/{info["bundle"]}.png"
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
data["apps"].append({
|
||||||
|
"name": app_name,
|
||||||
|
"type": 5, # type: dylib
|
||||||
|
"bundleId": f"com.mysign.{app_name.lower()}",
|
||||||
|
"bundleIdentifier": f"com.mysign.{app_name.lower()}",
|
||||||
|
"version": version,
|
||||||
|
"versionDate": date,
|
||||||
|
"fullDate": full_date,
|
||||||
|
"size": int(asset.size),
|
||||||
|
"down": asset.browser_download_url,
|
||||||
|
"downloadURL": asset.browser_download_url,
|
||||||
|
"developerName": "",
|
||||||
|
"localizedDescription": app_name,
|
||||||
|
"icon": "https://cdn1.realmzer.xyz//IMG_3830-tF.png",
|
||||||
|
"iconURL": "https://cdn1.realmzer.xyz//IMG_3830-tF.png"
|
||||||
|
})
|
||||||
|
|
||||||
|
data["apps"].sort(key=lambda x: x["fullDate"], reverse=True)
|
||||||
|
df.to_csv("bundleId.csv", index=False)
|
||||||
|
|
||||||
|
with open(out_file, 'w') as json_file:
|
||||||
|
json.dump(data, json_file, indent=4)
|
||||||
96
get_bundle_id.py
Normal file
96
get_bundle_id.py
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
import os
|
||||||
|
import zipfile
|
||||||
|
import plistlib
|
||||||
|
from tempfile import NamedTemporaryFile as NTF
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
# returns genre id
|
||||||
|
def save_appstore_icon(bundle: str) -> dict:
|
||||||
|
x = requests.get(f"https://itunes.apple.com/lookup?bundleId={bundle}&limit=1&country=US").json()
|
||||||
|
try:
|
||||||
|
icon_url = x["results"][0]["artworkUrl512"]
|
||||||
|
genres = x["results"][0]["genreIds"]
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
# type 1 = app
|
||||||
|
return {"genre": 1, "err": True} # invalid appstore app, will have to extract from ipa
|
||||||
|
|
||||||
|
with NTF() as tmp:
|
||||||
|
tmp.write(requests.get(icon_url).content)
|
||||||
|
with Image.open(tmp.name) as img:
|
||||||
|
img.save(f"icons/{bundle}.png", "PNG") # usually jpg, so we save as png instead
|
||||||
|
|
||||||
|
if "6014" in genres or any(genre.startswith("70") for genre in genres):
|
||||||
|
return {"genre": 2, "err": False} # type 2 = game
|
||||||
|
return {"genre": 1, "err": False}
|
||||||
|
|
||||||
|
|
||||||
|
# this is shit so gotta seperate into its own func lol
|
||||||
|
# TIL: the namelist doesnt always have the .app name??
|
||||||
|
def get_app_name(nl: list[str]) -> str:
|
||||||
|
for name in nl:
|
||||||
|
if ".app/" in name and len(name.split("/")) >= 2:
|
||||||
|
return "/".join(name.split("/")[:2])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
# uses same method as seashell cli:
|
||||||
|
# https://github.com/EntySec/SeaShell/blob/8ae1ecba722ba303c961c537633b663717fcfbe7/seashell/core/ipa.py#L189
|
||||||
|
def no_seashell(path: str) -> dict:
|
||||||
|
with zipfile.ZipFile(path) as zf:
|
||||||
|
app: str = get_app_name((nl := zf.namelist()))
|
||||||
|
|
||||||
|
if f"{app}/mussel" in nl:
|
||||||
|
return {"unsafe": 1}
|
||||||
|
|
||||||
|
# note: `CFBundleSignature` is now appearing in the real world?
|
||||||
|
# why is this even becoming an official key? whatever
|
||||||
|
|
||||||
|
with zf.open((pl_name := f"{app}/Info.plist")) as pl:
|
||||||
|
plist = plistlib.load(pl)
|
||||||
|
|
||||||
|
# if "CFBundleSignature" in plist:
|
||||||
|
# return {"unsafe": 1}
|
||||||
|
|
||||||
|
return {"pl": plist, "nl": nl, "pl_name": pl_name}
|
||||||
|
|
||||||
|
|
||||||
|
# if called, guaranteed that icon is not yet saved
|
||||||
|
def get_single_bundle_id(url, name = "temp.ipa") -> dict:
|
||||||
|
with open(name, "wb") as f:
|
||||||
|
f.write(requests.get(url).content)
|
||||||
|
|
||||||
|
os.makedirs("icons", exist_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert(zipfile.is_zipfile(name))
|
||||||
|
except AssertionError:
|
||||||
|
print(f"[!] bad zipfile: {os.path.basename(url)} ({url})")
|
||||||
|
return {"error": 1}
|
||||||
|
|
||||||
|
try:
|
||||||
|
assert("unsafe" not in (sscheck := no_seashell(name)))
|
||||||
|
except AssertionError:
|
||||||
|
print(f"[!] seashell detected in: {os.path.basename(url)} ({url})")
|
||||||
|
return {"error": 1}
|
||||||
|
|
||||||
|
with zipfile.ZipFile(name) as archive:
|
||||||
|
bundleId = sscheck["pl"]["CFBundleIdentifier"]
|
||||||
|
|
||||||
|
if (res := save_appstore_icon(bundleId))["err"]:
|
||||||
|
try:
|
||||||
|
icon_path = sscheck["pl"]["CFBundleIcons"]["CFBundlePrimaryIcon"]["CFBundleIconFiles"][0]
|
||||||
|
for name in sscheck["nl"]:
|
||||||
|
if icon_path in name:
|
||||||
|
icon_path = name # im so tired
|
||||||
|
break
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
# is this doing what i think it's doing..?
|
||||||
|
icon_path = f"{os.path.dirname(sscheck["pl_name"])}/{sscheck["pl"]["CFBundleIconFiles"][0]}"
|
||||||
|
|
||||||
|
with archive.open(icon_path) as orig, open(f"icons/{bundleId}.png", "wb") as new:
|
||||||
|
new.write(orig.read())
|
||||||
|
|
||||||
|
return {"bundle": bundleId, "genre": res["genre"]}
|
||||||
Loading…
Reference in a new issue