diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 54fb324c..cbf68d76 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -34,6 +34,7 @@ import json import time import yaml import copy +import asn1crypto.cms import defusedxml.ElementTree as ElementTree from datetime import datetime, timezone from argparse import ArgumentParser @@ -598,149 +599,8 @@ IPA_PERMISSIONS = [ ] -# known iOS app entitlements, source: -# https://developer.apple.com/documentation/bundleresources/entitlements -IPA_ENTITLEMENTS = [ - b"aps-environment", - b"com.apple.developer.ClassKit-environment", - b"com.apple.developer.applesignin", - b"com.apple.developer.aps-environment", - b"com.apple.developer.associated-appclip-app-identifiers", - b"com.apple.developer.associated-domains", - b"com.apple.developer.associated-domains.applinks.read-write", - b"com.apple.developer.authentication-services.autofill-credential-provider", - b"com.apple.developer.automated-device-enrollment.add-devices", - b"com.apple.developer.automatic-assessment-configuration", - b"com.apple.developer.avfoundation.multitasking-camera-access", - b"com.apple.developer.browser.app-installation", - b"com.apple.developer.carplay-audio", - b"com.apple.developer.carplay-charging", - b"com.apple.developer.carplay-communication", - b"com.apple.developer.carplay-maps", - b"com.apple.developer.carplay-messaging", - b"com.apple.developer.carplay-parking", - b"com.apple.developer.carplay-quick-ordering", - b"com.apple.developer.contacts.notes", - b"com.apple.developer.default-data-protection", - b"com.apple.developer.device-information.user-assigned-device-name", - b"com.apple.developer.devicecheck.appattest-environment", - b"com.apple.developer.driverkit", - b"com.apple.developer.driverkit.allow-any-userclient-access", - b"com.apple.developer.driverkit.allow-third-party-userclients", - b"com.apple.developer.driverkit.communicates-with-drivers", - b"com.apple.developer.driverkit.family.audio", - b"com.apple.developer.driverkit.family.block-storage-device", - b"com.apple.developer.driverkit.family.hid.device", - b"com.apple.developer.driverkit.family.hid.eventservice", - b"com.apple.developer.driverkit.family.networking", - b"com.apple.developer.driverkit.family.scsicontroller", - b"com.apple.developer.driverkit.family.serial", - b"com.apple.developer.driverkit.transport.hid", - b"com.apple.developer.driverkit.transport.pci", - b"com.apple.developer.driverkit.transport.usb", - b"com.apple.developer.driverkit.userclient-access", - b"com.apple.developer.endpoint-security.client", - b"com.apple.developer.endpoint-security.client", - b"com.apple.developer.exposure-notification", - b"com.apple.developer.family-controls", - b"com.apple.developer.fileprovider.testing-mode", - b"com.apple.developer.game-center", - b"com.apple.developer.group-session", - b"com.apple.developer.healthkit", - b"com.apple.developer.healthkit.access", - b"com.apple.developer.healthkit.background-delivery", - b"com.apple.developer.healthkit.recalibrate-estimates", - b"com.apple.developer.hid.virtual.device", - b"com.apple.developer.homekit", - b"com.apple.developer.icloud-container-development-container-identifiers", - b"com.apple.developer.icloud-container-environment", - b"com.apple.developer.icloud-container-identifiers", - b"com.apple.developer.icloud-services", - b"com.apple.developer.in-app-identity-presentment", - b"com.apple.developer.in-app-identity-presentment.merchant-identifiers", - b"com.apple.developer.in-app-payments", - b"com.apple.developer.journal.allow", - b"com.apple.developer.kernel.extended-virtual-addressing", - b"com.apple.developer.kernel.increased-memory-limit", - b"com.apple.developer.location.push", - b"com.apple.developer.mail-client", - b"com.apple.developer.managed-app-distribution.install-ui", - b"com.apple.developer.maps", - b"com.apple.developer.marketplace.app-installation", - b"com.apple.developer.matter.allow-setup-payload", - b"com.apple.developer.media-device-discovery-extension", - b"com.apple.developer.networking.HotspotConfiguration", - b"com.apple.developer.networking.custom-protocol", - b"com.apple.developer.networking.manage-thread-network-credentials", - b"com.apple.developer.networking.multicast", - b"com.apple.developer.networking.multipath", - b"com.apple.developer.networking.networkextension", - b"com.apple.developer.networking.networkextension", - b"com.apple.developer.networking.slicing.appcategory", - b"com.apple.developer.networking.slicing.trafficcategory", - b"com.apple.developer.networking.vmnet", - b"com.apple.developer.networking.vpn.api", - b"com.apple.developer.networking.wifi-info", - b"com.apple.developer.nfc.hce", - b"com.apple.developer.nfc.hce.default-contactless-app", - b"com.apple.developer.nfc.hce.iso7816.select-identifier-prefixes", - b"com.apple.developer.nfc.readersession.formats", - b"com.apple.developer.on-demand-install-capable", - b"com.apple.developer.parent-application-identifiers", - b"com.apple.developer.pass-type-identifiers", - b"com.apple.developer.playable-content", - b"com.apple.developer.proximity-reader.identity.display", - b"com.apple.developer.proximity-reader.identity.read", - b"com.apple.developer.push-to-talk", - b"com.apple.developer.sensitivecontentanalysis.client", - b"com.apple.developer.sensorkit.reader.allow", - b"com.apple.developer.severe-vehicular-crash-event", - b"com.apple.developer.siri", - b"com.apple.developer.storekit.external-link.account", - b"com.apple.developer.storekit.external-purchase", - b"com.apple.developer.storekit.external-purchase-link", - b"com.apple.developer.sustained-execution", - b"com.apple.developer.system-extension.install", - b"com.apple.developer.system-extension.redistributable", - b"com.apple.developer.team-identifier", - b"com.apple.developer.ubiquity-kvstore-identifier", - b"com.apple.developer.upi-device-validation", - b"com.apple.developer.user-management", - b"com.apple.developer.usernotifications.filtering", - b"com.apple.developer.video-subscriber-single-sign-on", - b"com.apple.developer.weatherkit", - b"com.apple.developer.web-browser", - b"com.apple.developer.web-browser.public-key-credential", - b"com.apple.external-accessory.wireless-configuration", - b"com.apple.security.app-sandbox", - b"com.apple.security.application-groups", - b"com.apple.security.automation.apple-events", - b"com.apple.security.cs.allow-dyld-environment-variables", - b"com.apple.security.cs.allow-jit", - b"com.apple.security.cs.allow-unsigned-executable-memory", - b"com.apple.security.cs.debugger", - b"com.apple.security.cs.disable-executable-page-protection", - b"com.apple.security.cs.disable-library-validation", - b"com.apple.security.device.audio-input", - b"com.apple.security.device.camera", - b"com.apple.security.hypervisor", - b"com.apple.security.personal-information.addressbook", - b"com.apple.security.personal-information.calendars", - b"com.apple.security.personal-information.location", - b"com.apple.security.personal-information.photos-library", - b"com.apple.security.smartcard", - b"com.apple.security.virtualization", - b"com.apple.smoot.subscriptionservice", - b"com.apple.vm.device-access", - b"com.apple.vm.hypervisor", - b"com.apple.vm.networking", - b"inter-app-audio", - b"keychain-access-groups", -] - - def parse_ipa(ipa_path, file_size, sha256): - from biplist import readPlist + import biplist ipa = { "apkName": os.path.basename(ipa_path), @@ -755,7 +615,7 @@ def parse_ipa(ipa_path, file_size, sha256): for info in ipa_zip.infolist(): if re.match("Payload/[^/]*.app/Info.plist", info.filename): with ipa_zip.open(info) as plist_file: - plist = readPlist(plist_file) + plist = biplist.readPlist(plist_file) ipa["name"] = plist['CFBundleName'] ipa["packageName"] = plist["CFBundleIdentifier"] # https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring @@ -768,12 +628,15 @@ def parse_ipa(ipa_path, file_size, sha256): ipa["ipa_permissions"][ipap] = str(plist[ipap]) if info.filename.endswith("/embedded.mobileprovision"): print("parsing", info.filename) - with ipa_zip.open(info) as mopro: - for line in mopro.readlines(): - for entitlement in IPA_ENTITLEMENTS: - if entitlement in line: - ipa['ipa_entitlements'].add(str(entitlement, encoding="utf-8")) - + with ipa_zip.open(info) as mopro_file: + mopro_content_info = cms.ContentInfo.load(mopro_file.read()) + mopro_payload_info = mopro_content_info['content'] + mopro_payload = mopro_payload_info['encap_content_info']['content'].native + mopro = biplist.readPlistFromString(mopro_payload) + # https://faq.altstore.io/distribute-your-apps/make-a-source#entitlements-array-of-strings + for entitlement in mopro.get('Entitlements', {}).keys(): + if entitlement not in ["com.app.developer.team-identifier", 'application-identifier']: + ipa["ipa_entitlements"].add(entitlement) return ipa @@ -1563,8 +1426,8 @@ def insert_localized_ios_app_metadata(apps_with_packages): fdroidserver.update.copy_ios_screenshots_to_repo(screenshots, package_name) # lookup icons, copy them and put them into app - icon_path = _get_ipa_icon(pathlib.Path('build') / package_name) - icon_dest = pathlib.Path('repo') / package_name / 'icon.png' # for now just assume png + icon_path = _get_ipa_icon(Path('build') / package_name) + icon_dest = Path('repo') / package_name / 'icon.png' # for now just assume png icon_stat = os.stat(icon_path) app['iconv2'] = { DEFAULT_LOCALE: { @@ -1777,7 +1640,7 @@ def _get_apk_icons_src(apkfile, icon_name): def _get_ipa_icon(src_dir): """Search source directory of an IPA project for the app icon.""" # parse app icon name from project config file - src_dir = pathlib.Path(src_dir) + src_dir = Path(src_dir) prj = next(src_dir.glob("**/project.pbxproj"), None) if not prj or not prj.exists(): return @@ -2688,7 +2551,7 @@ def altstore_index(apps, apks, config, repodir, indent=None): # idx["subtitle"] F-Droid doesn't have a corresponding value if config.get("repo_description"): idx['description'] = config['repo_description'] - if (pathlib.Path(repodir) / 'icons' / config['repo_icon']).exists(): + if (Path(repodir) / 'icons' / config['repo_icon']).exists(): idx['iconURL'] = f"{config['repo_url']}/icons/{config['repo_icon']}" # idx["headerURL"] F-Droid doesn't have a corresponding value # idx["website"] F-Droid doesn't have a corresponding value