Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature/resign-script] Resign Script #690

Merged
merged 10 commits into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions enterprise/resign/App/ad-hoc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Place your `unsigned.ipa` file in this folder, which should be signed for `ad-hoc` build.

After the resigning process, here you will find the `signed.ipa` file.
4 changes: 4 additions & 0 deletions enterprise/resign/App/app-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Place your `unsigned.ipa` file in this folder, which should be signed for `app-store` build.

After the resigning process, here you will find the `signed.ipa` file.

5 changes: 5 additions & 0 deletions enterprise/resign/Provisioning Files/ad-hoc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#### Place the following provisioning files in this folder, which was created for ad-hoc build:

- App.mobileprovision
- FileProvider.mobileprovision
- Intent.mobileprovision
5 changes: 5 additions & 0 deletions enterprise/resign/Provisioning Files/app-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#### Place the following provisioning files in this folder, which was created for the app-store:

- App.mobileprovision
- FileProvider.mobileprovision
- Intent.mobileprovision
58 changes: 58 additions & 0 deletions enterprise/resign/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Script to resign your iOS ownCloud App

This script allows you to resign the ownCloud App IPA file with a different Apple certificate.
Decide if you want to sign the app for Ad-Hoc (`ad-hoc`) installation or for the App Store(`app-store`).

## App IDs and Provisioning Files

1. You need to generate the following App IDs with `App Groups` enabled on the Apple Developer Portal `Identifiers` section:

- `com.yourcompany.ios-app`

- `com.yourcompany.ios-app.ownCloud-File-Provider`

- `com.yourcompany.ios-app.ownCloud-Intent`



This IDs must match with `Bundle Identifier` value for the related Xcode target.

2. Generate one App Group:

- `group.com.yourcompany.ios-app`



Please keep the prefix `group.` and append the bundle identifier of the app target.

3. Edit the App IDs and assign the App Group created on step 2.

4. Generate the mobile provisioning (App Store or Ad-Hoc) for both App IDs using a Distribution certificate (this certificate must be installed on the computer and its common name will be used as parameter on the script)

## Certificate

- Get the name of your signing certificate. In most cases this will be named `iPhone Distribution: YOUR COMPANY`.

## Instructions

1. Rename your `.ipa` file to `unsigned.ipa`

2. Put the `unsigned.ipa` on the folder `App/ad-hoc/` or `App/app-store/`

3. Put your mobile provisioning inside `Provisioning Files/ad-hoc/` or `Provisioning Files/app-store/`

4. The mobile provisioning must be named:

- `App.mobileprovision`
- `FileProvider.mobileprovision`
- `Intent.mobileprovision`

5. Execute the script

- `sh resignOwncloudApp "COMMON NAME DISTRIBUTION CERT" "ad-hoc"`

- `sh resignOwncloudApp "COMMON NAME DISTRIBUTION CERT" "app-store"`



Replace `"COMMON NAME DISTRIBUTION CERT"` with the name of your certificate, e.g. `"iPhone Distribution: YOUR COMPANY"`.
233 changes: 233 additions & 0 deletions enterprise/resign/resignOwncloudApp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#! /bin/bash

# Copyright (C) 2020, ownCloud GmbH.
#
# This code is covered by the GNU Public License Version 3.
#
# For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
# You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.

VERSION="1.0.0"

#Define output formats
BOLD="$(tput bold)"
UNDERLINED="$(tput smul)"
NOTUNDERLINED="$(tput rmul)"
WARN="$(tput setaf 1)"
SUCCESS="$(tput setaf 2)"
INFO="$(tput setaf 3)"
NC="$(tput sgr0)" # No Color


usage()
{
echo "Usage: $0 CERTIFICATE_IDENTITY METHOD"
echo " $0 \"Certificate Identity\" ad-hoc"
echo " $0 \"Certificate Identity\" app-store"
echo "Version: ${VERSION}"
echo ""
echo "Found Certificate Identities:"
echo " Fingerprint \"Certificate Identity\""
echo " -----------------------------------------------------------------"
security find-identity -pcodesigning -v
exit 1
}

#Check if all required parameters exist
if [ $# -lt 2 ]; then
usage
fi
if ! [[ "$2" =~ ^(ad-hoc|app-store)$ ]]; then
usage
fi

echo
echo "${BOLD}${SUCCESS}ownCloud iOS-App Resigning${NC}"
echo "Version ${VERSION}"
echo
echo "${SUCCESS}Starting resign process…${NC}"
echo ""

#Define variables
IDENTITY=$1
METHOD=$2
BUILD_DIR="App"
NAME_FINAL_IPA="signed.ipa"
UNSIGNED_IPA="$BUILD_DIR/$METHOD/unsigned.ipa"
ERROR_SHA1=0
FINAL_IPA="$BUILD_DIR/$METHOD/$NAME_FINAL_IPA"
APPTEMP="$BUILD_DIR/$METHOD/apptemp"
APPPAYLOAD="$APPTEMP/Payload"
APPDIR="$APPPAYLOAD/ownCloud.app"
PROVISIONING_DIR="Provisioning Files"

DISTRIBUTION_MOBILEPROVISION="$PROVISIONING_DIR/$METHOD/App.mobileprovision"
FILEPROVIDER_MOBILEPROVISION="$PROVISIONING_DIR/$METHOD/FileProvider.mobileprovision"
INTENT_MOBILEPROVISION="$PROVISIONING_DIR/$METHOD/Intent.mobileprovision"

declare -a MOBILEPROVISIONS=( "$DISTRIBUTION_MOBILEPROVISION" "$FILEPROVIDER_MOBILEPROVISION" "$INTENT_MOBILEPROVISION" );
declare -a ENTITLEMENTS=( "ownCloud.entitlements" "ownCloud_File_Provider.entitlements" "ownCloud_Intents.entitlements" );
declare -a LOCATIONS=( "$APPDIR" "$APPDIR/PlugIns/ownCloud File Provider.appex" "$APPDIR/PlugIns/ownCloud Intents.appex" );
declare -a BUNDLEIDS=();

# Delete previous temporal app folder if exist
if [ -d "$APPTEMP" ]; then
rm -rf "$APPTEMP"
fi

if [ ! -f "$UNSIGNED_IPA" ]; then
echo "${WARN}Error: can't find $UNSIGNED_IPA in the current directory${NC}"
exit 1
fi

# Get certificate SHA-1
CERT_SHA_1=`security find-certificate -c "$IDENTITY" -Z | grep "^SHA-1" | cut -d: -f 2 | xargs`
# Create temp directory
mkdir $APPTEMP

echo "${UNDERLINED}${SUCCESS}Checking Provisioning Profiles:${NOTUNDERLINED}"

for a in "${MOBILEPROVISIONS[@]}"
do
if [ ! -f "./$a" ]; then
echo "${WARN}Error: can't find $a in the current directory${NC}"
exit 1
else
# Convert provisioning profile to plist
security cms -D -i "$a" > "$APPTEMP/tmp.plist"
# Get provisioning SHA-1
PROV_SHA_1=`/usr/libexec/PlistBuddy -c "Print :DeveloperCertificates:0" $APPTEMP/tmp.plist | openssl x509 -inform der -fingerprint | grep "^SHA1" | cut -d= -f 2 | ruby -ne 'puts $_.split(":").join'`

if [ "$CERT_SHA_1" = "$PROV_SHA_1" ]; then
echo "${SUCCESS}Provisioning fingerprint matches with certificate:${NC}"
echo "${INFO}$a${NC}"
echo ""
else
echo ""
echo "${WARN}The provisioning fingerprint does not match with the certificate fingerprint:${NC}"
echo "Provisioning Profile: ${INFO}$a${NC}"
echo "Certificate Fingerprint: ${INFO}$CERT_SHA_1${NC}"
echo "Provisioning Fingerprint: ${INFO}$PROV_SHA_1${NC}"
ERROR_SHA1=1
fi
fi
done

if [ "$ERROR_SHA1" = 1 ]; then
echo ""
echo "Please check that you are using the correct certificate identity and the provisioning profile was signed with the chosen certificate identity."
echo "${WARN}Exit resigning. Please fix the errors above.${NC}"
exit
fi

export PATH=$PATH:/usr/libexec

# Unzip ipa
echo "${SUCCESS}Unzipping ipa…${NC}"
echo ""
unzip -q "$UNSIGNED_IPA" -d "$APPTEMP" || { echo "${WARN}Failed to unzip ipa file${NC}"; exit 1; }


# Profile
# security cms -D -i ~/Downloads/App.mobileprovision > ~/Downloads/App.plist
# /usr/libexec/PlistBuddy -c "Print :DeveloperCertificates:0" ~/Downloads/App.plist | openssl x509 -inform der -fingerprint | grep "^SHA1" | cut -d= -f 2 | ruby -ne 'puts $_.split(":").join'


for (( i=0; i<${#MOBILEPROVISIONS[@]}; i++ ));
do
echo "${UNDERLINED}${SUCCESS}Module:${NOTUNDERLINED}"
echo "${INFO}${LOCATIONS[$i]}${NC}"
echo ""
echo "Provisioning: ${INFO}${MOBILEPROVISIONS[$i]}${NC}"
echo "Entitlements: ${INFO}${ENTITLEMENTS[$i]}${NC}"
echo ""

# Duplicate each mobile provision as embedded.mobileprovision and move to correct destination folder
cp "${MOBILEPROVISIONS[$i]}" "$BUILD_DIR/$METHOD/embedded.mobileprovision"

{
mv "$BUILD_DIR/$METHOD/embedded.mobileprovision" "${LOCATIONS[$i]}"
} || { # catch
echo "${WARN}ERROR${NC}"
}

echo "${SUCCESS}Creating entitlements…${NC}"
# Create all the necessary entitlements
PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i "./${MOBILEPROVISIONS[$i]}") > "${ENTITLEMENTS[$i]}"
TEAMID=`PlistBuddy -c "print com.apple.developer.team-identifier " "${ENTITLEMENTS[$i]}"`
echo "TeamId: ${INFO}$TEAMID${NC}"
APPGROUP=`PlistBuddy -c "print com.apple.security.application-groups:0 " "${ENTITLEMENTS[$i]}"`
echo "AppGroup: ${INFO}$APPGROUP${NC}"
APP_ID_PREFIX=`PlistBuddy -c "print :ApplicationIdentifierPrefix:0" /dev/stdin <<< $(security cms -D -i "./${MOBILEPROVISIONS[$i]}") `
echo "ApplicationIdentifierPrefix: ${INFO}$APP_ID_PREFIX${NC}"

# Modify entitlements
PlistBuddy -c "Set keychain-access-groups:0 $APP_ID_PREFIX.$APPGROUP" "${ENTITLEMENTS[$i]}"

echo ""
echo "${SUCCESS}Modify ${INFO}${LOCATIONS[$i]}/Info.plist${NC}…"
# Modify Info.plists
BUNDLEID=( `PlistBuddy -c "print application-identifier " ${ENTITLEMENTS[$i]} | sed 's/^.\{11\}//'` )
echo "Set Bundle ID: ${INFO}${BUNDLEID}${NC}"
PlistBuddy -c "Set CFBundleIdentifier ${BUNDLEID}" "${LOCATIONS[$i]}/Info.plist"

# Modify Info.plists with ownCloud custom variables
PlistBuddy -c "Set OCAppGroupIdentifier $APPGROUP" "${LOCATIONS[$i]}/Info.plist"
PlistBuddy -c "Set OCKeychainAccessGroupIdentifier $APPGROUP" "${LOCATIONS[$i]}/Info.plist"
PlistBuddy -c "Set OCAppIdentifierPrefix $APP_ID_PREFIX." "${LOCATIONS[$i]}/Info.plist"

# Remove old Code Signatures
rm -rf "${LOCATIONS[$i]}/_CodeSignature"

echo ""
done

echo "${SUCCESS}Resign App, Extensions and Frameworks…${NC}"
echo ""

#Resign Swift & Frameworks Libraries
ls "${APPDIR}/Frameworks" | while read file
do
/usr/bin/codesign -fv -s "$IDENTITY" "${APPDIR}/Frameworks/$file" --entitlements "${ENTITLEMENTS[0]}"
done

# Resign everything
for (( i=(${#MOBILEPROVISIONS[@]} - 1); i>=0; i-- ));
do
/usr/bin/codesign -fv -s "$IDENTITY" "${LOCATIONS[$i]}" --entitlements "${ENTITLEMENTS[$i]}"
done


# Generate new Payload
echo ""
echo "${SUCCESS}Packing new ipa…${NC}"
pushd "$APPTEMP"
zip -q -r "$NAME_FINAL_IPA" *
popd

mv "$APPTEMP/$NAME_FINAL_IPA" $FINAL_IPA

echo ""
echo "${SUCCESS}Removing temporal items…${NC}"

# Delete temporal payload folder
echo "Removing temporal folder $APPTEMP"
rm -rf "$APPTEMP"
echo "Removing payload folder $APPPAYLOAD"
rm -rf "$APPPAYLOAD"

# Delete temporal entitlements files
for (( i=0; i<${#ENTITLEMENTS[@]}; i++ ));
do
if [ -f "${ENTITLEMENTS[$i]}" ]; then
echo "Removing temporal ${ENTITLEMENTS[$i]}"
rm -rf "${ENTITLEMENTS[$i]}"
fi

done

echo
echo "${SUCCESS}Signed file:${NC} ${FINAL_IPA}"
echo
echo "${BOLD}${SUCCESS}Signing complete.${NC}"
echo