#!/usr/bin/env python3 """Validate Tarnax's embedded profile, including Apple's wildcard App IDs.""" import argparse import datetime import fnmatch import plistlib import sys def validate(app, profile, device=None, distribution=False): bundle = app.get('CFBundleIdentifier') if bundle != 'net.absdev.Tarnax': raise ValueError('This script installs only net.absdev.Tarnax.') entitlements = profile.get('Entitlements', {}) pattern = entitlements.get('application-identifier', '') # The App ID prefix can differ from the Team ID on older Apple accounts. prefixes = profile.get('ApplicationIdentifierPrefix', []) if not pattern or not any(fnmatch.fnmatchcase(prefix + '.' + bundle, pattern) for prefix in prefixes): raise ValueError('Profile does not match Tarnax.') expiry = profile.get('ExpirationDate') if expiry is None: raise ValueError('Profile has no expiration date.') if expiry.tzinfo is None: expiry = expiry.replace(tzinfo=datetime.timezone.utc) if expiry <= datetime.datetime.now(datetime.timezone.utc): raise ValueError('The app provisioning profile has expired.') devices = profile.get('ProvisionedDevices', []) if not devices: raise ValueError('Profile does not include registered devices.') if device and device not in devices: raise ValueError('This iPhone is not included in the app provisioning profile. Register it and export again.') if distribution and entitlements.get('get-task-allow', False): raise ValueError('Distribution IPA has debugging enabled.') def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('app_plist') parser.add_argument('profile_plist') parser.add_argument('--device') parser.add_argument('--distribution', action='store_true') args = parser.parse_args() try: with open(args.app_plist, 'rb') as f: app = plistlib.load(f) with open(args.profile_plist, 'rb') as f: profile = plistlib.load(f) validate(app, profile, args.device, args.distribution) except (ValueError, OSError, plistlib.InvalidFileException) as error: sys.exit(str(error)) print('Verified Tarnax', app['CFBundleShortVersionString'], 'build', app['CFBundleVersion']) print('Registered devices:', len(profile['ProvisionedDevices'])) print('Profile expiry:', profile['ExpirationDate'].isoformat()) if __name__ == '__main__': main()