#!/usr/bin/env python

"""Codesign utility"""

import argparse
import subprocess
import os
import time
import shutil
import json

parser = argparse.ArgumentParser(description = 'Codesign utility for Ninja builds')
parser.add_argument('file', type=str,
                    help = 'Bundle/package to sign')
parser.add_argument('--target', type=str,
                    help = 'Target',
                    choices = ['macos', 'ios', 'android'],
                    default = '')
parser.add_argument('--bundle', type=str,
                    help = 'Bundle identifier (OSX/iOS)',
                    default = '')
parser.add_argument('--organisation', type=str,
                    help = 'Organisation identifier (OSX/iOS)',
                    default = '')
parser.add_argument('--provisioning', type=str,
                    help = 'Provisioning profile (OSX/iOS)',
                    default = '')
parser.add_argument('--builddir', type=str,
                    help = 'Build directory (OSX/iOS)',
                    default = '')
parser.add_argument('--binname', type=str,
                    help = 'Binary name (OSX/iOS)',
                    default = '')
parser.add_argument('--zipfile', type=str,
                    help = 'Zip file (Android)',
                    default = '')
parser.add_argument('--tsacert', type=str,
                    help = 'TSA cert (Android)',
                    default = '')
parser.add_argument('--tsa', type=str,
                    help = 'TSA (Android)',
                    default = '')
parser.add_argument('--keystore', type=str,
                    help = 'Keystore (Android)',
                    default = '')
parser.add_argument('--keystorepass', type=str,
                    help = 'Keystore password (Android)',
                    default = '')
parser.add_argument('--keyalias', type=str,
                    help = 'Key alias (Android)',
                    default = '')
parser.add_argument('--keypass', type=str,
                    help = 'Key password (Android)',
                    default = '')
parser.add_argument('--jarsigner', type=str,
                    help = 'JAR signer (Android)',
                    default = 'jarsigner')
parser.add_argument('--prefs', type=str,
                    help = 'Preferences file',
                    default = '')
parser.add_argument('--config', type=str,
                    help = 'Build configuration',
                    default = '')
parser.add_argument('--entitlements', type=str,
                    help = 'Entitlements file',
                    default = '')
options = parser.parse_args()

androidprefs = {}
iosprefs = {}
macosprefs = {}


def parse_prefs( prefsfile ):
  global androidprefs
  global iosprefs
  global macosprefs
  if not os.path.isfile( prefsfile ):
    return
  file = open( prefsfile, 'r' )
  prefs = json.load( file )
  file.close()
  if 'android' in prefs:
    androidprefs = prefs['android']
  if 'ios' in prefs:
    iosprefs = prefs['ios']
  if 'macos' in prefs:
    macosprefs = prefs['macos']


def codesign_ios():
  if not 'organisation' in iosprefs:
    iosprefs['organisation'] = options.organisation
  if not 'bundleidentifier' in iosprefs:
    iosprefs['bundleidentifier'] = options.bundle
  if not 'provisioning' in iosprefs:
    iosprefs['provisioning'] = options.provisioning

  sdkdir = subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '--show-sdk-path' ] ).decode().strip().splitlines()[-1]
  entitlements = os.path.join( sdkdir, 'Entitlements.plist' )
  plistpath = os.path.join( options.builddir, 'Entitlements.xcent' )

  platformpath = subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '--show-sdk-platform-path' ] ).decode().strip().splitlines()[-1]
  localpath = platformpath + "/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
  plutil = "PATH=" + localpath + " " + subprocess.check_output( [ 'xcrun', '--sdk', 'iphoneos', '-f', 'plutil' ] ).decode().strip().splitlines()[-1]

  shutil.copyfile( entitlements, plistpath )
  os.system( plutil + ' -convert xml1 ' + plistpath )

  f = open( plistpath, 'r' )
  lines = [ line.strip( '\n\r' ) for line in f ]
  f.close()

  for i in range( 0, len( lines ) ):
    if lines[i].find( '$(AppIdentifierPrefix)' ) != -1:
      lines[i] = lines[i].replace( '$(AppIdentifierPrefix)', iosprefs['organisation'] + '.' )
    if lines[i].find( '$(CFBundleIdentifier)' ) != -1:
      lines[i] = lines[i].replace( '$(CFBundleIdentifier)', iosprefs['bundleidentifier'] )
    if lines[i].find( '$(binname)' ) != -1:
      lines[i] = lines[i].replace( '$(binname)', options.binname )

  with open( plistpath, 'w' ) as plist_file:
    for line in lines:
      if options.config != 'deploy' and line == '</dict>':
        plist_file.write( '\t<key>get-task-allow</key>\n' )
        plist_file.write( '\t<true/>\n' )
      plist_file.write( line + '\n' )
    plist_file.close()

  if os.path.isfile( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) ):
    os.remove( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) )

  os.system( '/usr/bin/codesign --force --sign "' + iosprefs['signature'] + '" --entitlements ' + plistpath + ' ' + options.file )

  if os.path.isfile( os.path.join( options.file, '_CodeSignature', 'CodeResources' ) ):
    os.utime( os.path.join( options.file, '_CodeSignature', 'CodeResources' ), None )
    os.utime( os.path.join( options.file, '_CodeSignature' ), None )
    os.utime( options.file, None )


def codesign_macos():
  if not 'organisation' in macosprefs:
    macosprefs['organisation'] = options.organisation
  if not 'bundleidentifier' in macosprefs:
    macosprefs['bundleidentifier'] = options.bundle
  if not 'provisioning' in macosprefs:
    macosprefs['provisioning'] = options.provisioning
  if not 'entitlements' in macosprefs:
    macosprefs['entitlements'] = options.entitlements

  codesign_allocate = subprocess.check_output( [ 'xcrun', '--sdk', 'macosx', '-f', 'codesign_allocate' ] ).decode().strip().splitlines()[-1]
  sdkdir = subprocess.check_output( [ 'xcrun', '--sdk', 'macosx', '--show-sdk-path' ] ).decode().strip().splitlines()[-1]
  entitlements = os.path.join( sdkdir, 'Entitlements.plist' )

  if os.path.isfile( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) ):
    os.remove( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) )

  if 'signature' in macosprefs:
    command = 'export CODESIGN_ALLOCATE=' + codesign_allocate + '; /usr/bin/codesign --force --sign "' + macosprefs['signature'] + '" -o runtime '
    if ('entitlements' in macosprefs) and (macosprefs['entitlements'] != '') and (macosprefs['entitlements'] != 'none'):
      command = command + '--entitlements ' + macosprefs['entitlements'] + ' --generate-entitlement-der '
    command = command + options.file
    # print(command)
    os.system(command)

  if os.path.isfile( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ) ):
    os.utime( os.path.join( options.file, 'Contents', '_CodeSignature', 'CodeResources' ), None )
    os.utime( os.path.join( options.file, 'Contents', '_CodeSignature' ), None )
    os.utime( os.path.join( options.file, 'Contents' ), None )
    os.utime( options.file, None )


def codesign_android():
  if not 'tsacert' in androidprefs:
    androidprefs['tsacert'] = options.tsacert
  if not 'tsa' in androidprefs:
    androidprefs['tsa'] = options.tsa
  if not 'keystore' in androidprefs:
    androidprefs['keystore'] = options.keystore
  if not 'keystorepass' in androidprefs:
    androidprefs['keystorepass'] = options.keystorepass
  if not 'keyalias' in androidprefs:
    androidprefs['keyalias'] = options.keyalias
  if not 'keypass' in androidprefs:
    androidprefs['keypass'] = options.keypass
  if not 'jarsigner' in androidprefs:
    androidprefs['jarsigner'] = options.jarsigner

  timestamp = ''
  if androidprefs['tsacert'] != '':
    timestamp = '-tsacert ' + androidprefs['tsacert']
  elif androidprefs['tsa'] != '':
    timestamp = '-tsa ' + androidprefs['tsa']

  proxy = ''
  if 'proxy' in androidprefs and androidprefs['proxy'] != '' and androidprefs['proxy'] != 'None':
    proxy = androidprefs['proxy']
    if proxy != '' and proxy != 'None':
      defstr = "-J-Dhttp.proxy"
      url = urlparse.urlparse(proxy)
      if url.scheme == 'https':
        defstr = "-J-Dhttps.proxy"
      host = url.netloc
      port = ''
      username = ''
      password = ''
      if '@' in host:
        username, host = host.split(':', 1)
        password, host = host.split('@', 1)
      if ':' in host:
        host, port = host.split(':', 1)
      proxy = defstr + "Host=" + host
      if port != '':
        proxy += " " + defstr + "Port=" + port
      if username != '':
        proxy += " " + defstr + "User=" + username
      if password != '':
        proxy += " " + defstr + "Password=" + password

  signcmd = androidprefs['jarsigner'] + ' ' + timestamp + ' -sigalg SHA1withRSA -digestalg SHA1 -keystore ' + androidprefs['keystore'] + ' -storepass ' + androidprefs['keystorepass'] + ' -keypass ' + androidprefs['keypass'] + ' -signedjar ' + options.file + ' ' + options.zipfile + ' ' + androidprefs['keyalias'] + ' ' + proxy
  os.system(signcmd)


parse_prefs( options.prefs )

if options.target == 'ios':
  codesign_ios()
elif options.target == 'macos':
  codesign_macos()
elif options.target == 'android':
  codesign_android()
