Skip to content

Instantly share code, notes, and snippets.

@larryhou
Last active February 5, 2025 10:52
Show Gist options
  • Select an option

  • Save larryhou/767fbd4c0a1071a4637121ffd6ad275f to your computer and use it in GitHub Desktop.

Select an option

Save larryhou/767fbd4c0a1071a4637121ffd6ad275f to your computer and use it in GitHub Desktop.
#!/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