Files
ios/tools/verify_ipa.py
T

34 lines
1.6 KiB
Python
Raw Normal View History

"""Verify a thin ARM64 iPhone IPA, independently of the macOS build environment."""
import pathlib
import plistlib
import struct
import sys
import zipfile
path = pathlib.Path(sys.argv[1])
with zipfile.ZipFile(path) as archive:
assert archive.testzip() is None, "Corrupt ZIP member"
prefix = "Payload/MusicBridge.app/"
info = plistlib.loads(archive.read(prefix + "Info.plist"))
assert info["CFBundleSupportedPlatforms"] == ["iPhoneOS"], "Not an iPhone device build"
assert info["CFBundleIdentifier"] == "ru.yukinoki.musicbridge", "Unexpected bundle ID"
assert info["MinimumOSVersion"] == "17.0", "Unexpected minimum iOS version"
executable = info["CFBundleExecutable"]
assert executable == "MusicBridge", "Unexpected executable"
binary = archive.read(prefix + executable)
magic, cpu = struct.unpack_from("<II", binary)
assert magic == 0xFEEDFACF and cpu == 0x0100000C, "Expected ARM64 Mach-O executable"
# ARM64 can also be a simulator build: check LC_BUILD_VERSION's platform field.
command_count = struct.unpack_from("<I", binary, 16)[0]
offset = 32
platforms = []
for _ in range(command_count):
command, size = struct.unpack_from("<II", binary, offset)
assert size >= 8 and offset + size <= len(binary), "Invalid Mach-O load command"
if command == 0x32:
platforms.append(struct.unpack_from("<I", binary, offset + 8)[0])
offset += size
assert platforms == [2], "Mach-O is not built for iOS devices"
print(f"PASS: {path.name}: valid IPA, iPhoneOS ARM64, iOS 17+, ru.yukinoki.musicbridge.")
print("Requires local signing with Sideloadly before installation on an iPhone.")