Last active
February 5, 2025 10:52
-
-
Save larryhou/767fbd4c0a1071a4637121ffd6ad275f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| #encoding:utf-8 | |
| from __future__ import print_function | |
| import os, sys, re, io, json, base64 | |
| __author__ = 'larryhou' | |
| def load_provision(provision_file, options): | |
| import tempfile | |
| plist = tempfile.mktemp(suffix='.plist') | |
| os.environ['XMLLINT_INDENT'] = ' ' * 4 | |
| command = 'security cms -D -i \'{}\' | xmllint --format - | sed "s/data>/string>/g" | sed "s/date>/string>/g" | tee {}'.format(provision_file, plist) | |
| if not options.verbose: | |
| command = '{} >/dev/null'.format(command) | |
| assert os.system(command) == 0 | |
| assert os.system('plutil -convert json {}'.format(plist)) == 0 | |
| data = json.load(fp=open(plist, 'r')) | |
| if options.verbose: | |
| print(json.dumps(data, ensure_ascii=False, indent=4)) | |
| os.remove(plist) | |
| return data | |
| def dump_provision(provision_file, options): | |
| print('>>> {}'.format(provision_file)) | |
| data = load_provision(provision_file, options) | |
| settings = { | |
| u'DEVELOPMENT_TEAM': data.get('TeamIdentifier')[0], | |
| u'PROVISIONING_PROFILE': data.get('UUID'), | |
| u'PROVISIONING_PROFILE_SPECIFIER': data.get('Name'), | |
| u'APPLICATION_IDENTIFIER': data.get('Entitlements').get('application-identifier'), | |
| u'PRODUCT_BUNDLE_IDENTIFIER': data.get('Entitlements').get('application-identifier').split('.', 1)[-1], | |
| } | |
| for name, value in settings.items(): | |
| print(u'{}=\'{}\''.format(name, value)) | |
| from OpenSSL import crypto | |
| certificates = [] | |
| for cert_data in data.get('DeveloperCertificates'): | |
| cert = crypto.load_certificate(crypto.FILETYPE_ASN1, base64.b64decode(cert_data)) | |
| SHA1 = cert.digest('sha1').decode('ascii').replace(':', '') | |
| subject = cert.get_subject() | |
| print(u'CODE_SIGN_IDENTITY=\'{}\''.format(subject.CN)) | |
| certificates.append((SHA1, subject.UID, subject.OU, subject.CN)) | |
| for r in certificates: | |
| print(u'# sha1={} uid={} ou={} cn=\'{}\''.format(*r)) | |
| index = 1 | |
| for device in data.get('ProvisionedDevices', {}): | |
| print('[{:02d}] {}'.format(index, device)) | |
| index += 1 | |
| print() | |
| def main(): | |
| import argparse, sys | |
| arguments = argparse.ArgumentParser() | |
| arguments.add_argument('--verbose', '-v', action='store_true') | |
| arguments.add_argument('--provision-file', '-f', nargs='+') | |
| arguments.add_argument('--scan', '-s', action='store_true') | |
| options = arguments.parse_args(sys.argv[1:]) | |
| import os.path as p | |
| if options.scan: | |
| provision_path = os.path.expanduser('~/Library/MobileDevice/Provisioning Profiles') | |
| provision_list = [] | |
| for file_name in os.listdir(provision_path): | |
| if not re.match(r'^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}.mobileprovision$', file_name): continue | |
| provision_list.append(os.path.join(provision_path, file_name)) | |
| try: | |
| provision_list.sort(lambda a, b: -1 if p.getmtime(a) > p.getmtime(b) else 1) | |
| except: | |
| import functools | |
| provision_list.sort(key=functools.cmp_to_key(lambda a, b: -1 if p.getmtime(a) > p.getmtime(b) else 1)) | |
| for provision_file in provision_list: | |
| dump_provision(provision_file, options) | |
| else: | |
| for provision_file in options.provision_file: | |
| dump_provision(provision_file, options) | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment