#!/bin/bash
# This script was tested on 10.11.1 with Xcode 7.1 installed, your mileage may vary.
echo "iOS App Signer rev. 35"
if [[ "$#" -lt 2 ]]; then
  echo "Usage: "$(basename "$0")" (file name/url) (Developer Identity) [(.mobileprovision file)] [(new app id)]"
  echo ""
  echo "You can ommit the mobileprovision file if you just want to re-sign the app."
  echo "It is also possible to specify a new app id, this is only possible if you have a wildcard .mobileprovision file."
  echo "The application id will be changed to the mobileprovision file if it is not a wildcard."
  echo "It is also possible to change the app id without specifying a mobileprovision file, just use two quotes \"\""
  echo ""
  echo "Supported filetypes are .deb, .ipa, and app bundles"
  exit 1
fi

LIST_BINARY_EXTENSIONS="dylib so 0 vis pvr framework"
TEMP="$(mktemp -d)"
OUTPUT="$TEMP/out"
mkdir "$OUTPUT" 2>&1
CURRENT_PATH="$(pwd)"

Extension="${1##*.}"
FilePath="$1"

if [[ "$1" == http*://* ]] && [[ ("$Extension" == "deb" || "$Extension" == "ipa") ]]; then
  curl "$1" > "$TEMP/app.$Extension" || (echo "Error Downloading: $1"; exit 1)
  FilePath="$TEMP/app.$Extension"
fi

if [[ ! -e "$FilePath" ]]; then
    echo "File not found: $1"
    exit 1
fi

case "$Extension" in
  deb )
    echo "Extracting .deb file"
    mkdir "$TEMP/deb" 2>&1
    cd "$TEMP/deb" 2>&1
    ar -x "$FilePath" >/dev/null 2>&1 || (echo "Error extracting .deb"; exit 1)
    
    tar -xf $TEMP/deb/data.tar* 2>&1 || (echo "Error untarring .deb data file"; exit 1)
    
    mv "$TEMP/deb/Applications/" "$OUTPUT/Payload/" 2>&1
    ;;
  ipa )
    echo "Unzipping .ipa file"
    unzip -q "$FilePath" -d "$OUTPUT" 2>&1 || (echo "Error extracting $FilePath"; exit 1)
    ;;
  app )
    if [ ! -d "$FilePath" ]; then
      echo "$FilePath is not a directory"
      exit 1
    fi
    echo "Copying .app to temp folder" 2>&1
    mkdir "$OUTPUT/Payload" 2>&1
    cp -r "$FilePath" "$OUTPUT/Payload" 2>&1
    ;;
  *) echo "Filetype not supported"; exit 1
esac

AppBundleName="$(ls "$OUTPUT/Payload/" | sort -n | head -1)"
EntitlementsPlist="$OUTPUT/entitlements.plist"
AppIdentifier="$(defaults read "$OUTPUT/Payload/$AppBundleName/Info.plist" CFBundleIdentifier)"

if [[ -n "$3" ]] && [[ -e "$3" ]]; then
  if [[ -e "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" ]]; then
    echo "Deleted .mobileprovision in app bundle"
    rm "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" 2>&1
  fi
  
  echo "Copy .mobileprovision to app bundle"
  cp "$3" "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" 2>&1
fi

if [[ -e "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" ]]; then
  MobileProvisionIdentifier="$(egrep -a -A 2 application-identifier "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" | grep string | sed -e 's/<string>//' -e 's/<\/string>//' -e 's/ //')"
  MobileProvisionIdentifier="${MobileProvisionIdentifier#*.}"
  
  if [[ "$MobileProvisionIdentifier" != "*" ]] && [[ "$MobileProvisionIdentifier" != "$AppIdentifier" ]] && [[ -z "$4" ]]; then
    defaults write "$OUTPUT/Payload/$AppBundleName/Info.plist" CFBundleIdentifier "$MobileProvisionIdentifier" 2>&1
    AppIdentifier="$MobileProvisionIdentifier"
    echo "Changed app identifier to $AppIdentifier to match the provisioning profile"
  fi
else
  MobileProvisionIdentifier="*"
fi

if [[ -n "$4" ]]; then
  if [[ "$MobileProvisionIdentifier" != "*" ]] && [[ "$MobileProvisionIdentifier" != "$4" ]]; then
    echo "You wanted to change the app identifier to $4 but your provisioning profile would not allow this! ($MobileProvisionIdentifier)"
    exit 1
  fi
  defaults write "$OUTPUT/Payload/$AppBundleName/Info.plist" CFBundleIdentifier "$4" 2>&1
  AppIdentifier="$4"
  echo "Changed app identifier to $AppIdentifier"
fi

defaults read "$OUTPUT/Payload/$AppBundleName/Info.plist" CFBundleResourceSpecification > /dev/null &&
  defaults delete "$OUTPUT/Payload/$AppBundleName/Info.plist" CFBundleResourceSpecification 2>&1

if [[ -e "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" ]]; then
  security cms -D -i "$OUTPUT/Payload/$AppBundleName/embedded.mobileprovision" > "$TEMP/mobileprovision.plist"
  /usr/libexec/PlistBuddy -c "Print :Entitlements" "$TEMP/mobileprovision.plist" -x > "$EntitlementsPlist"
fi

cd "$OUTPUT/Payload/"
if [ -e "$EntitlementsPlist" ]; then
  echo "Signing with entitlements"
  echo "-------------------------"
  cat "$EntitlementsPlist"
  echo "-------------------------"
else
  echo "Signing without entitlements"
fi
for binext in $LIST_BINARY_EXTENSIONS; do
  for signfile in $(find "./$AppBundleName" -name "*.$binext" -type f); do
    if [ -e "$EntitlementsPlist" ]; then
      codesign -vvv -fs "$2" --no-strict "--entitlements=$EntitlementsPlist" "$signfile" 2>&1
    else
      codesign -vvv -fs "$2" --no-strict "$signfile" 2>&1
    fi
  done
done

if [ -e "$EntitlementsPlist" ]; then
  codesign -vvv -fs "$2" --no-strict "--entitlements=$EntitlementsPlist"  "./$AppBundleName" 2>&1
else
  codesign -vvv -fs "$2" --no-strict   "./$AppBundleName" 2>&1
fi

if [[ -e "$CURRENT_PATH/$AppIdentifier-signed.ipa" ]]; then
  echo "Deleted existing output file"
  rm "$CURRENT_PATH/$AppIdentifier-signed.ipa"
fi
cd "$OUTPUT"
echo "Packaging..."
zip -qry "$CURRENT_PATH/$AppIdentifier-signed.ipa" "."
cd "$CURRENT_PATH"
echo "Doing some housekeeping..."
rm -rf "$TEMP"
echo "Done, the package is located at $CURRENT_PATH/$AppIdentifier-signed.ipa"