Skip to content

Instantly share code, notes, and snippets.

@seaders
Created June 30, 2014 13:22
Show Gist options
  • Save seaders/806d1a7ec47eceea1e1b to your computer and use it in GitHub Desktop.
Save seaders/806d1a7ec47eceea1e1b to your computer and use it in GitHub Desktop.
Python ipa resigner script
import argparse
import sys
import os
import shutil
import re
import shlex
import subprocess
import plistlib
from functools import wraps
ENTITLEMENTS_NAME = 'Entitlements.plist'
EMBEDDED_PROV_NAME = 'embedded.mobileprovision'
PAYLOAD_KEY = 'Payload'
APP_ID_KEY = 'application-identifier'
APP_EXT = '.app'
PLIST_START = '<?xml'
PLIST_END = '</plist>'
def rm(path):
shutil.rmtree(path, True)
try:
os.unlink(path)
except:
pass
def execCommand(cmd, cwd=None, exit_on_fail=True, shout=False,
ignoreErrors=False, ignoreError='', path=None, home=None):
path = path or execCommand.path
home = home or execCommand.home
cwd = cwd or execCommand.cwd
print '({}) {}'.format(cwd, cmd)
args = shlex.split(cmd)
try:
process = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, cwd=cwd,
env=dict(PATH=path, HOME=home))
except OSError as(_, strerror):
if not ignoreErrors:
print ' !!! Error executing command >' + cmd + ': ' + strerror
if exit_on_fail:
sys.exit(1)
output, error = process.communicate()
if ignoreError == error:
output += ignoreError
error = ''
if '' != error and not ignoreErrors:
print '!!! Error executing command\n\t{}\n\t\'{}\'\n\t\'{}\''.\
format(cmd, error, output)
if exit_on_fail:
sys.exit(1)
output = output.strip()
if shout:
print '{} {}\n\t{}'.format(output, process.returncode, error)
return output, error, process.returncode
execCommand.path = '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin'
execCommand.home = '/var/lib/jenkins'
execCommand.cwd = '.'
def parseArgs(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
# Get command line args
parser = argparse.ArgumentParser(description='Resign IPA')
parser.add_argument('--input', '-i', help='Input IPA')
parser.add_argument('--output', '-o', help='Output IPA')
parser.add_argument('--mobile_provision', '-mp',
help='Mobile Provision file')
parser.add_argument('--dev_cert', '-dc',
help='Developer Certificate Name')
parser.add_argument('--user_home', '-uh',
help='Home dir for keychain user')
if 11 != len(sys.argv):
parser.print_help()
sys.exit(1)
args = parser.parse_args()
execCommand.home = args.user_home
fn(args.input, args.output, args.dev_cert, args.mobile_provision)
return wrapper
def entitlementsFromProvision(path):
with open(path) as f:
data = f.read()
xml = data[data.find(PLIST_START):data.find(PLIST_END) + len(PLIST_END)]
pl = plistlib.readPlistFromString(xml)
return pl['Entitlements']
@parseArgs
def main(ipaInput, ipaOutput, dev_cert, mobile_provision):
ipaInput, ipaOutput = (os.path.abspath(a) for a in (ipaInput, ipaOutput))
output_dir = os.path.dirname(ipaOutput)
payload_dir = os.path.join(output_dir, PAYLOAD_KEY)
entitlement_file = os.path.join(output_dir, ENTITLEMENTS_NAME)
execCommand.cwd = output_dir
def cleanup(initial=False):
rm(payload_dir)
rm(entitlement_file)
if initial:
rm(ipaOutput)
cleanup(True)
execCommand('unzip {}'.format(ipaInput), output_dir)
for _, folders, _ in os.walk(payload_dir):
appName = re.search(r'^(.*)\.app$', folders[0]).group(1)
break
appDir = os.path.join(payload_dir, appName + APP_EXT)
embedded_prov = os.path.join(appDir, EMBEDDED_PROV_NAME)
rm(os.path.join(appDir, '_CodeSignature'))
rm(os.path.join(appDir, 'CodeResources'))
theirEntitlements = entitlementsFromProvision(embedded_prov)
ourEntitlements = entitlementsFromProvision(mobile_provision)
ourEntitlements['com.apple.developer.team-identifier'] = \
ourEntitlements['application-identifier'].partition('.')[0]
shutil.copy(mobile_provision, embedded_prov)
plistlib.writePlist(ourEntitlements, entitlement_file)
execCommand(
'/usr/bin/codesign -f -s "{}" --entitlements {} --resource-rules '
'"{}/ResourceRules.plist" "{}"'.
format(dev_cert, entitlement_file, appDir, appDir),
output_dir,
ignoreError='{}: replacing existing signature\n'.format(appDir)
)
execCommand('zip -qr {} {}'.format(ipaOutput, PAYLOAD_KEY), output_dir)
print '\naltering their entitlements\n\t{}\nto our entitlements\n\t{}'.\
format(theirEntitlements, ourEntitlements)
cleanup()
if __name__ == '__main__':
main()
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment