sigh/lib/assets/resign.sh in fastlane_hotfix-2.165.1 vs sigh/lib/assets/resign.sh in fastlane_hotfix-2.187.0

- old
+ new

@@ -73,10 +73,15 @@ # 1. enable (re)signing of OnDemandResources when ipa has been built for the appstore # # new features August 2020 # 1. fixes usage for users with GNU-sed in their $PATH # +# new features May 2021 +# 1. fix entitlements merging when changing team +# +# new features June 2021 +# 1. fix the way app entitlements are extracted # Logging functions log() { # Make sure it returns 0 code even when verose mode is off (test 1) @@ -344,11 +349,11 @@ fi done } # Find the bundle identifier contained inside a provisioning profile -function bundle_id_for_provison { +function bundle_id_for_provision { local FULL_BUNDLE_ID=$(PlistBuddy -c 'Print :Entitlements:application-identifier' /dev/stdin <<< "$(security cms -D -i "$1")") checkStatus echo "${FULL_BUNDLE_ID#*.}" } @@ -382,11 +387,11 @@ if [[ ! -e "$PROVISION" ]]; then error "Provisioning profile '$PROVISION' file does not exist" fi - local BUNDLE_ID=$(bundle_id_for_provison "$PROVISION") + local BUNDLE_ID=$(bundle_id_for_provision "$PROVISION") add_provision_for_bundle_id "$PROVISION" "$BUNDLE_ID" } # Load bundle identifiers from provisioning profiles for ARG in "${RAW_PROVISIONS[@]}"; do @@ -432,11 +437,11 @@ warning "No provisioning profile for application: '$APP_PATH' with bundle identifier '${BUNDLE_IDENTIFIER:-$CURRENT_BUNDLE_IDENTIFIER}'" fi error "Use the -p option (example: -p com.example.app=xxxx.mobileprovision)" fi - local PROVISION_BUNDLE_IDENTIFIER=$(bundle_id_for_provison "$NEW_PROVISION") + local PROVISION_BUNDLE_IDENTIFIER=$(bundle_id_for_provision "$NEW_PROVISION") # Use provisioning profile's bundle identifier if [ "$BUNDLE_IDENTIFIER" == "" ]; then # shellcheck disable=SC2049 if [[ "$PROVISION_BUNDLE_IDENTIFIER" =~ \* ]]; then @@ -578,11 +583,11 @@ REF_BUNDLE_ID=$(PlistBuddy -c "Print ${key}" "$APP_PATH/Info.plist" 2>/dev/null) if [ -n "$REF_BUNDLE_ID" ]; then # Found a reference bundle id, now get the corresponding provisioning profile for this bundle id REF_PROVISION=$(provision_for_bundle_id "$REF_BUNDLE_ID") # Map to the new bundle id - NEW_REF_BUNDLE_ID=$(bundle_id_for_provison "$REF_PROVISION") + NEW_REF_BUNDLE_ID=$(bundle_id_for_provision "$REF_PROVISION") # Change if not the same and if doesn't contain wildcard # shellcheck disable=SC2049 if [[ "$REF_BUNDLE_ID" != "$NEW_REF_BUNDLE_ID" ]] && ! [[ "$NEW_REF_BUNDLE_ID" =~ \* ]]; then log "Updating nested app or extension reference for ${key} key from ${REF_BUNDLE_ID} to ${NEW_REF_BUNDLE_ID}" PlistBuddy -c "Set ${key} $NEW_REF_BUNDLE_ID" "$APP_PATH/Info.plist" @@ -634,10 +639,24 @@ checkStatus log "\nApp entitlements for ${APP_PATH}:" log "$(cat "$APP_ENTITLEMENTS")" + # Get the old and new app identifier (prefix) + APP_ID_KEY="application-identifier" + # Extract just the identifier from the value + # Use the fact that we are after some identifer, which is always at the start of the string + OLD_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$APP_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') + NEW_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') + + # Get the old and the new team ID + # Old team ID is not part of app entitlements, have to get it from old embedded provisioning profile + security cms -D -i "$TEMP_DIR/old-embedded.mobileprovision" > "$TEMP_DIR/old-embedded-profile.plist" + OLD_TEAM_ID=$(PlistBuddy -c "Print :TeamIdentifier:0" "$TEMP_DIR/old-embedded-profile.plist") + # New team ID is part of profile entitlements + NEW_TEAM_ID=$(PlistBuddy -c "Print com.apple.developer.team-identifier" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') + log "Patching profile entitlements with values from app entitlements" PATCHED_ENTITLEMENTS="$TEMP_DIR/patchedEntitlements" # Start with using what comes in provisioning profile entitlements before patching cp -f "$PROFILE_ENTITLEMENTS" "$PATCHED_ENTITLEMENTS" @@ -652,24 +671,18 @@ DENYLISTED_KEYS=(\ # PP list identifiers inconsistent with app-defined ones and this key does not seem to appear in IPA entitlements, so ignore it "com.apple.developer.icloud-container-development-container-identifiers" \ # This key has an invalid generic value in PP (actual value is set by Xcode during export), see dedicated processing a few blocks below "com.apple.developer.icloud-container-environment" \ - # PP list identifiers inconsistent with app-defined ones, must use App entitlements value - "com.apple.developer.icloud-container-identifiers" \ # PP enable all available services and not app-defined ones, must use App entitlements value "com.apple.developer.icloud-services" \ # Was already denylisted in previous version, but has someone ever seen this key in a PP? "com.apple.developer.restricted-resource-mode" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.nfc.readersession.formats" \ - # PP list a single TeamID.* identifier and not app-defined ones, must use App entitlements value - "com.apple.developer.pass-type-identifiers" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.siri" \ - # PP list identifiers inconsistent with app-defined ones, must use App entitlements value - "com.apple.developer.ubiquity-container-identifiers" \ # PP define a generic TeamID.* identifier and not the app-defined one, must use App entitlements value "com.apple.developer.ubiquity-kvstore-identifier" \ # If actually used by the App, this value will be set in its entitlements "inter-app-audio" \ # PP define a generic TeamID.* identifier and not the app-defined one, must use App entitlements value @@ -678,12 +691,10 @@ "com.apple.developer.homekit" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.healthkit" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.healthkit.access" \ - # PP list identifiers inconsistent with app-defined ones, must use App entitlements value - "com.apple.developer.in-app-payments" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.networking.vpn.api" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.networking.HotspotConfiguration" \ # PP list all available extensions and not app-defined ones, must use App entitlements value @@ -692,44 +703,49 @@ "com.apple.developer.networking.multipath" \ # PP enable all domains via a non-AppStore-compliant '*' value, must use App entitlements value "com.apple.developer.associated-domains" \ # If actually used by the App, this value will be set in its entitlements "com.apple.developer.default-data-protection" \ - # PP seem to list the same groups as the App, but use App entitlements value to be sure - "com.apple.security.application-groups" \ # Was already denylisted in previous version, seems to be an artifact from an old Xcode release "com.apple.developer.maps" \ # If actually used by the App, this value will be set in its entitlements "com.apple.external-accessory.wireless-configuration" ) + # If we change team while resigning, we have no other choice than to use the following entitlements from the PP instead of the App + # because they are based on unique identifiers (defined in the developer portal) that can't be shared between teams + if [[ "$OLD_TEAM_ID" != "$NEW_TEAM_ID" ]]; then + warning "WARNING: Changing team while resigning" + warning "WARNING: Using these entitlements from the provisioning profile instead of the existing app:" + warning "WARNING: App Groups, Merchant IDs (Apple Pay In-App Payments), iCloud Containers, Pass Type IDs (Wallet)" + warning "WARNING: If these capabilities are enabled, make sure AppID and provisioning profile are properly configured" + # For Pass Types, PP only list a single TeamID.* identifier and not the potential restricted list defined in the existing App + # but we can't guess the new identifiers to be used, so this generic value is better than nothing and should be fine for most apps + warning "WARNING: Resigned app will allow all pass types from the new team, even if old app only allowed a restricted list" + else + DENYLISTED_KEYS+=(\ + "com.apple.security.application-groups" \ + "com.apple.developer.in-app-payments" \ + "com.apple.developer.ubiquity-container-identifiers" \ + "com.apple.developer.icloud-container-identifiers" \ + "com.apple.developer.pass-type-identifiers" \ + ) + fi + # Denylisted keys must not be included into new profile, so remove them from patched profile for KEY in "${DENYLISTED_KEYS[@]}"; do log "Removing denylisted key: $KEY" PlistBuddy -c "Delete $KEY" "$PATCHED_ENTITLEMENTS" 2>/dev/null done - # Get the old and new app identifier (prefix) - APP_ID_KEY="application-identifier" - # Extract just the identifier from the value - # Use the fact that we are after some identifier, which is always at the start of the string - OLD_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$APP_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') - NEW_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') - - # Get the old and the new team ID - # Old team ID is not part of app entitlements, have to get it from old embedded provisioning profile - security cms -D -i "$TEMP_DIR/old-embedded.mobileprovision" > "$TEMP_DIR/old-embedded-profile.plist" - OLD_TEAM_ID=$(PlistBuddy -c "Print :TeamIdentifier:0" "$TEMP_DIR/old-embedded-profile.plist") - # New team ID is part of profile entitlements - NEW_TEAM_ID=$(PlistBuddy -c "Print com.apple.developer.team-identifier" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n') - # List of rules for transferring entitlements from app to profile plist # The format for each enty is "KEY[|ID_TYPE]" # Where KEY is the plist key, e.g. "keychain-access-groups" # and ID_TYPE is optional part separated by '|' that specifies what value to patch: # TEAM_ID - patch the TeamIdentifierPrefix # APP_ID - patch the AppIdentifierPrefix + # ICLOUD_ENV - patch the target iCloud Environment # Patching means replacing old value from app entitlements with new value from provisioning profile # For example, for KEY=keychain-access-groups the ID_TYPE=APP_ID # Which means that old app ID prefix in keychain-access-groups will be replaced with new app ID prefix # There can be only one ID_TYPE specified # If entitlements use more than one ID type for single entitlement, then this way of resigning will not work @@ -738,42 +754,63 @@ "com.apple.developer.associated-domains" \ "com.apple.developer.default-data-protection" \ "com.apple.developer.healthkit" \ "com.apple.developer.healthkit.access" \ "com.apple.developer.homekit" \ - "com.apple.developer.icloud-container-environment" \ - "com.apple.developer.icloud-container-identifiers" \ + "com.apple.developer.icloud-container-environment|ICLOUD_ENV" \ "com.apple.developer.icloud-services" \ - "com.apple.developer.in-app-payments" \ "com.apple.developer.networking.HotspotConfiguration" \ "com.apple.developer.networking.multipath" \ "com.apple.developer.networking.networkextension" \ "com.apple.developer.networking.vpn.api" \ "com.apple.developer.nfc.readersession.formats" \ - "com.apple.developer.pass-type-identifiers|TEAM_ID" \ "com.apple.developer.siri" \ - "com.apple.developer.ubiquity-container-identifiers" \ "com.apple.developer.ubiquity-kvstore-identifier|TEAM_ID" \ "com.apple.external-accessory.wireless-configuration" \ - "com.apple.security.application-groups" \ "inter-app-audio" \ - "keychain-access-groups|APP_ID") + "keychain-access-groups|APP_ID" \ + ) + # If we change team while resigning, we have no other choice than to use the following entitlements from the PP instead of the App + # because they are based on unique identifiers (defined in the developer portal) that can't be shared between teams + # If we don't change team while resigning, we should use the following entitlements from the existing App and not from the PP + if [[ "$OLD_TEAM_ID" == "$NEW_TEAM_ID" ]]; then + ENTITLEMENTS_TRANSFER_RULES+=(\ + "com.apple.security.application-groups" \ + "com.apple.developer.in-app-payments" \ + "com.apple.developer.ubiquity-container-identifiers" \ + "com.apple.developer.icloud-container-identifiers" \ + "com.apple.developer.pass-type-identifiers|TEAM_ID" \ + ) + fi + # Loop over all the entitlement keys that need to be transferred from app entitlements for RULE in "${ENTITLEMENTS_TRANSFER_RULES[@]}"; do KEY=$(echo "$RULE" | cut -d'|' -f1) ID_TYPE=$(echo "$RULE" | cut -d'|' -f2) # Get the entry from app's entitlements # Read it with PlistBuddy as XML, then strip the header and <plist></plist> part - ENTITLEMENTS_VALUE="$(PlistBuddy -x -c "Print $KEY" "$APP_ENTITLEMENTS" 2>/dev/null | /usr/bin/sed -e 's,.*<plist[^>]*>\(.*\)</plist>,\1,g')" + ENTITLEMENTS_VALUE="$(PlistBuddy -x -c "Print $KEY" "$APP_ENTITLEMENTS" 2>/dev/null | tr -d '\n' | /usr/bin/sed -e 's,.*<plist[^>]*>\(.*\)</plist>,\1,g')" if [[ -z "$ENTITLEMENTS_VALUE" ]]; then log "No value for '$KEY'" continue fi - if [[ "$KEY" == "com.apple.developer.icloud-container-environment" ]]; then + log "App entitlements value for key '$KEY':" + log "$ENTITLEMENTS_VALUE" + + # Patch the ID value if specified + if [[ "$ID_TYPE" == "APP_ID" ]]; then + # Replace old value with new value in patched entitlements + log "Replacing old app ID '$OLD_APP_ID' with new app ID '$NEW_APP_ID'" + ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_APP_ID/$NEW_APP_ID/g") + elif [[ "$ID_TYPE" == "TEAM_ID" ]]; then + # Replace old team identifier with new value + log "Replacing old team ID '$OLD_TEAM_ID' with new team ID '$NEW_TEAM_ID'" + ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_TEAM_ID/$NEW_TEAM_ID/g") + elif [[ "$ID_TYPE" == "ICLOUD_ENV" ]]; then # Add specific iCloud Environment key to patched entitlements # This value is set by Xcode during export (manually selected for Development and AdHoc, automatically set to Production for Store) # Would need an additional dedicated option to specify the iCloud environment to be used (Development or Production) # For now, we assume Production is to be used when signing with a Distribution certificate, Development if not local certificate_name=$CERTIFICATE @@ -786,52 +823,35 @@ certificate_name="$(/usr/bin/sed -E s/[^\"]+\"\([^\"]+\)\".*/\\1/ <<< $certificate_matches )" log "Certificate name: $certificate_name" fi fi + OLD_ICLOUD_ENV=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e 's,<string>\(.*\)</string>,\1,g') if [[ "$certificate_name" =~ "Distribution:" ]]; then - ICLOUD_ENV="Production" + NEW_ICLOUD_ENV="Production" else - ICLOUD_ENV="Development" + NEW_ICLOUD_ENV="Development" fi - log "Overriding value for $KEY" - log "Old value: $ENTITLEMENTS_VALUE" - log "New value: $ICLOUD_ENV" - ENTITLEMENTS_VALUE="$ICLOUD_ENV" + log "Replacing iCloud environment '$OLD_ICLOUD_ENV' with '$NEW_ICLOUD_ENV'" + ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_ICLOUD_ENV/$NEW_ICLOUD_ENV/g") fi - log "App entitlements value for key '$KEY':" - log "$ENTITLEMENTS_VALUE" - # Remove the entry for current key from profisioning profile entitlements (if exists) PlistBuddy -c "Delete $KEY" "$PATCHED_ENTITLEMENTS" 2>/dev/null # Add new entry to patched entitlements # plutil needs dots in the key path to be escaped (e.g. com\.apple\.security\.application-groups) # otherwise it interprets they key path as nested keys # TODO: Should be able to replace with echo ${KEY//\./\\\\.} and remove shellcheck disable directive # shellcheck disable=SC2001 - PLUTIL_KEY=$(echo "$KEY" | /usr/bin/sed 's/\./\\\./g') + PLUTIL_KEY=$(echo "$KEY" | /usr/bin/sed -e 's/\./\\\./g') plutil -insert "$PLUTIL_KEY" -xml "$ENTITLEMENTS_VALUE" "$PATCHED_ENTITLEMENTS" - - # Patch the ID value if specified - if [[ "$ID_TYPE" == "APP_ID" ]]; then - # Replace old value with new value in patched entitlements - log "Replacing old app identifier prefix '$OLD_APP_ID' with new value '$NEW_APP_ID'" - /usr/bin/sed -i .bak "s/$OLD_APP_ID/$NEW_APP_ID/g" "$PATCHED_ENTITLEMENTS" - elif [[ "$ID_TYPE" == "TEAM_ID" ]]; then - # Replace old team identifier with new value - log "Replacing old team ID '$OLD_TEAM_ID' with new team ID: '$NEW_TEAM_ID'" - /usr/bin/sed -i .bak "s/$OLD_TEAM_ID/$NEW_TEAM_ID/g" "$PATCHED_ENTITLEMENTS" - else - continue - fi done # Replace old bundle ID with new bundle ID in patched entitlements # Read old bundle ID from the old Info.plist which was saved for this purpose OLD_BUNDLE_ID="$(PlistBuddy -c "Print :CFBundleIdentifier" "$TEMP_DIR/oldInfo.plist")" - NEW_BUNDLE_ID="$(bundle_id_for_provison "$NEW_PROVISION")" + NEW_BUNDLE_ID="$(bundle_id_for_provision "$NEW_PROVISION")" log "Replacing old bundle ID '$OLD_BUNDLE_ID' with new bundle ID '$NEW_BUNDLE_ID' in patched entitlements" # Note: ideally we'd match against the opening <string> tag too, but this isn't possible # because $OLD_BUNDLE_ID and $NEW_BUNDLE_ID do not include the team ID prefix which is # present in the entitlements file. # e.g. <string>AB1GP98Q19.com.example.foo</string>