resignios 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,943 @@
1
+ #!/bin/bash
2
+ # shellcheck disable=SC2155
3
+
4
+ # Copyright (c) 2011 Float Mobile Learning
5
+ # http://www.floatlearning.com/
6
+ # Extension Copyright (c) 2013 Weptun Gmbh
7
+ # http://www.weptun.de
8
+ #
9
+ # Extended by Ronan O Ciosoig January 2012
10
+ #
11
+ # Extended by Patrick Blitz, April 2013
12
+ #
13
+ # Extended by John Turnipseed and Matthew Nespor, November 2014
14
+ # http://nanonation.net/
15
+ #
16
+ # Extended by Nicolas Bachschmidt, October 2015
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining
19
+ # a copy of this software and associated documentation files (the "Software"),
20
+ # to deal in the Software without restriction, including without limitation
21
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
22
+ # and/or sell copies of the Software, and to permit persons to whom the
23
+ # Software is furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included
26
+ # in all copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
32
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
33
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
34
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
+ #
36
+ # Please let us know about any improvements you make to this script!
37
+ # ./floatsign source "iPhone Distribution: Name" -p "path/to/profile" [-d "display name"] [-e entitlements] [-k keychain] [-b "BundleIdentifier"] outputIpa
38
+ #
39
+ #
40
+ # Modifed 26th January 2012
41
+ #
42
+ # new features January 2012:
43
+ # 1. change the app display name
44
+ #
45
+ # new features April 2013
46
+ # 1. specify the target bundleId on the command line
47
+ # 2. correctly handles entitlements for keychain-enabled resigning
48
+ #
49
+ # new features November 2014
50
+ # 1. now re-signs embedded iOS frameworks, if present, prior to re-signing the application itself
51
+ # 2. extracts the team-identifier from provisioning profile and uses it to update previous entitlements
52
+ # 3. fixed bug in packaging if -e flag is used
53
+ # 4. renamed 'temp' directory and made it a variable so it can be easily modified
54
+ # 5. various code formatting and logging adjustments
55
+ #
56
+ # new features October 2015
57
+ # 1. now re-signs nested applications and app extensions, if present, prior to re-signing the application itself
58
+ # 2. enables the -p option to be used more than once
59
+ # 3. ensures the provisioning profile's bundle-identifier matches the app's bundle identifier
60
+ # 4. extracts the entitlements from the provisioning profile
61
+ # 5. copy the entitlements as archived-expanded-entitlements.xcent inside the app bundle (because Xcode does too)
62
+ #
63
+ # new features November 2018
64
+ # 1. only create the archived-expanded-entitlements.xcent file if the version of Xcode < 9.3 as Xcode 10 does not create it.
65
+ #
66
+ # new features January 2019
67
+ # 1. fixed bug where the com.apple.icloud-container-environment entitlement was being assigned an incorrect value
68
+ #
69
+ # new features March 2019
70
+ # 1. two more fixes for only creating the archived-expanded-entitlements.xcent file if the version of Xcode < 9.3 as Xcode 10 does not create it.
71
+ #
72
+ # new features June 2020
73
+ # 1. enable (re)signing of OnDemandResources when ipa has been built for the appstore
74
+ #
75
+ # new features August 2020
76
+ # 1. fixes usage for users with GNU-sed in their $PATH
77
+ #
78
+ # new features May 2021
79
+ # 1. fix entitlements merging when changing team
80
+ #
81
+ # new features June 2021
82
+ # 1. fix the way app entitlements are extracted
83
+ #
84
+ # new features October 2021
85
+ # 1. change codesign signatue to use --generate-entitlement-der to include DER encoded entitlements
86
+
87
+ # Logging functions
88
+
89
+ log() {
90
+ # Make sure it returns 0 code even when verose mode is off (test 1)
91
+ # To use like [[ condition ]] && log "x" && something
92
+ if [[ -n "$VERBOSE" ]]; then echo -e "$@"; else test 1; fi
93
+ }
94
+
95
+ error() {
96
+ echo "$@" >&2
97
+ exit 1
98
+ }
99
+
100
+ warning() {
101
+ echo "$@" >&2
102
+ }
103
+
104
+ function checkStatus {
105
+
106
+ # shellcheck disable=SC2181
107
+ if [ $? -ne 0 ]; then
108
+ error "Encountered an error, aborting!"
109
+ fi
110
+ }
111
+
112
+ usage() {
113
+ echo -e "Usage: $(basename "$0") source identity -p|--provisioning provisioning" >&2
114
+ echo -e "\t\t[-e|--entitlements entitlements]" >&2
115
+ echo -e "\t\t[-k|--keychain keychain]" >&2
116
+ echo -e "\t\t[-d|--display-name displayName]" >&2
117
+ echo -e "\t\t[-n|--version-number version]" >&2
118
+ echo -e "\t\t[--short-version shortVersion]" >&2
119
+ echo -e "\t\t[--bundle-version bundleVersion]" >&2
120
+ echo -e "\t\t[-b|--bundle-id bundleId]" >&2
121
+ echo -e "\t\t[--use-app-entitlements]" >&2
122
+ echo -e "\t\toutputIpa" >&2
123
+ echo "Usage: $(basename "$0") -h|--help" >&2
124
+ echo "Options:" >&2
125
+ echo -e "\t-p, --provisioning provisioning\t\tProvisioning profile option, may be provided multiple times." >&2
126
+ echo -e "\t\t\t\t\t\tYou can specify provisioning profile file name." >&2
127
+ echo -e "\t\t\t\t\t\t\t-p xxx.mobileprovision" >&2
128
+ echo "" >&2
129
+ echo -e "\t\t\t\t\t\tAlternatively you may provide multiple provisioning profiles if the application contains" >&2
130
+ echo -e "\t\t\t\t\t\tnested applications or app extensions, which need their own provisioning" >&2
131
+ echo -e "\t\t\t\t\t\tprofile. You can do so by providing -p option multiple times specifying" >&2
132
+ echo -e "\t\t\t\t\t\told bundle identifier and new provisioning profile for that bundle id joined with '='." >&2
133
+ echo -e "\t\t\t\t\t\t\t-p com.main-app=main-app.mobileprovision" >&2
134
+ echo -e "\t\t\t\t\t\t\t-p com.nested-app=nested-app.mobileprovision" >&2
135
+ echo -e "\t\t\t\t\t\t\t-p com.nested-extension=nested-extension.mobileprovision" >&2
136
+ echo "" >&2
137
+ echo -e "\t-e, --entitlements entitlements\t\tSpecify entitlements file path for code signing." >&2
138
+ echo -e "\t-k, --keychain keychain\t\t\tSpecify keychain for code signing." >&2
139
+ echo -e "\t-d, --display-name displayName\t\tSpecify new display name." >&2
140
+ echo -e "\t\t\t\t\t\t\tWarning: will apply for all nested apps and extensions." >&2
141
+ echo -e "\t-n, --version-number version\t\tSpecify new version number." >&2
142
+ echo -e "\t\t\t\t\t\t\tWill set CFBundleShortVersionString and CFBundleVersion values in Info.plist." >&2
143
+ echo -e "\t\t\t\t\t\t\tWill apply for all nested apps and extensions." >&2
144
+ echo -e "\t --short-version shortVersion\tSpecify new short version string (CFBundleShortVersionString)." >&2
145
+ echo -e "\t\t\t\t\t\t\tWill apply for all nested apps and extensions." >&2
146
+ echo -e "\t\t\t\t\t\t\tCan't use together with '-n, --version-number' option." >&2
147
+ echo -e "\t --bundle-version bundleVersion\tSpecify new bundle version (CFBundleVersion) number." >&2
148
+ echo -e "\t\t\t\t\t\t\tWill apply for all nested apps and extensions." >&2
149
+ echo -e "\t\t\t\t\t\t\tCan't use together with '-n, --version-number' option." >&2
150
+ echo -e "\t-b, --bundle-id bundleId\t\tSpecify new bundle identifier (CFBundleIdentifier)." >&2
151
+ echo -e "\t\t\t\t\t\t\tWarning: will NOT apply for nested apps and extensions." >&2
152
+ echo -e "\t --use-app-entitlements\t\tExtract app bundle codesigning entitlements and combine with entitlements from new provisionin profile." >&2
153
+ echo -e "\t\t\t\t\t\t\tCan't use together with '-e, --entitlements' option." >&2
154
+ echo -e "\t --remove-plugins\t\t\tRemove all plugins." >&2
155
+ echo -e "\t--keychain-path path\t\t\tSpecify the path to a keychain that /usr/bin/codesign should use." >&2
156
+ echo -e "\t-v, --verbose\t\t\t\tVerbose output." >&2
157
+ echo -e "\t-h, --help\t\t\t\tDisplay help message." >&2
158
+ exit 2
159
+ }
160
+
161
+ if [ $# -lt 3 ]; then
162
+ usage
163
+ fi
164
+
165
+ ORIGINAL_FILE="$1"
166
+ CERTIFICATE="$2"
167
+ ENTITLEMENTS=
168
+ BUNDLE_IDENTIFIER=""
169
+ DISPLAY_NAME=""
170
+ KEYCHAIN=""
171
+ VERSION_NUMBER=""
172
+ SHORT_VERSION=
173
+ BUNDLE_VERSION=
174
+ KEYCHAIN_PATH=
175
+ RAW_PROVISIONS=()
176
+ PROVISIONS_BY_ID=()
177
+ DEFAULT_PROVISION=""
178
+ TEMP_DIR="_floatsignTemp"
179
+ USE_APP_ENTITLEMENTS=""
180
+ REMOVE_PLUGINS=""
181
+ XCODE_VERSION="$(xcodebuild -version | grep "Xcode" | /usr/bin/cut -f 2 -d ' ')"
182
+
183
+ # List of plist keys used for reference to and from nested apps and extensions
184
+ NESTED_APP_REFERENCE_KEYS=(":WKCompanionAppBundleIdentifier" ":NSExtension:NSExtensionAttributes:WKAppBundleIdentifier")
185
+
186
+ # options start index
187
+ shift 2
188
+
189
+ # Parse args
190
+ while [ "$1" != "" ]; do
191
+ case $1 in
192
+ -p | --provisioning )
193
+ shift
194
+ RAW_PROVISIONS+=("$1")
195
+ ;;
196
+ -e | --entitlements )
197
+ shift
198
+ ENTITLEMENTS="$1"
199
+ ;;
200
+ -d | --display-name )
201
+ shift
202
+ DISPLAY_NAME="$1"
203
+ ;;
204
+ -b | --bundle-id )
205
+ shift
206
+ BUNDLE_IDENTIFIER="$1"
207
+ ;;
208
+ -k | --keychain )
209
+ shift
210
+ KEYCHAIN="$1"
211
+ ;;
212
+ -n | --version-number )
213
+ shift
214
+ VERSION_NUMBER="$1"
215
+ ;;
216
+ --short-version )
217
+ shift
218
+ SHORT_VERSION="$1"
219
+ ;;
220
+ --bundle-version )
221
+ shift
222
+ BUNDLE_VERSION="$1"
223
+ ;;
224
+ --use-app-entitlements )
225
+ USE_APP_ENTITLEMENTS="YES"
226
+ ;;
227
+ --remove-plugins )
228
+ REMOVE_PLUGINS="YES"
229
+ ;;
230
+ --keychain-path )
231
+ shift
232
+ KEYCHAIN_PATH="$1"
233
+ ;;
234
+ -v | --verbose )
235
+ VERBOSE="--verbose"
236
+ ;;
237
+ -h | --help )
238
+ usage
239
+ ;;
240
+ * )
241
+ [[ -n "$NEW_FILE" ]] && error "Multiple output file names specified!"
242
+ [[ -z "$NEW_FILE" ]] && NEW_FILE="$1"
243
+ ;;
244
+ esac
245
+
246
+ # Next arg
247
+ shift
248
+ done
249
+
250
+ KEYCHAIN_FLAG=
251
+ if [ -n "$KEYCHAIN_PATH" ]; then
252
+ KEYCHAIN_FLAG="--keychain $KEYCHAIN_PATH"
253
+ fi
254
+
255
+ # Log the options
256
+ for provision in "${RAW_PROVISIONS[@]}"; do
257
+ if [[ "$provision" =~ .+=.+ ]]; then
258
+ log "Specified provisioning profile: '${provision#*=}' for bundle identifier: '${provision%%=*}'"
259
+ else
260
+ log "Specified provisioning profile: '$provision'"
261
+ fi
262
+ done
263
+
264
+ log "Original file: '$ORIGINAL_FILE'"
265
+ log "Certificate: '$CERTIFICATE'"
266
+ [[ -n "${DISPLAY_NAME}" ]] && log "Specified display name: '$DISPLAY_NAME'"
267
+ [[ -n "${ENTITLEMENTS}" ]] && log "Specified signing entitlements: '$ENTITLEMENTS'"
268
+ [[ -n "${BUNDLE_IDENTIFIER}" ]] && log "Specified bundle identifier: '$BUNDLE_IDENTIFIER'"
269
+ [[ -n "${KEYCHAIN}" ]] && log "Specified keychain to use: '$KEYCHAIN'"
270
+ [[ -n "${VERSION_NUMBER}" ]] && log "Specified version number to use: '$VERSION_NUMBER'"
271
+ [[ -n "${SHORT_VERSION}" ]] && log "Specified short version to use: '$SHORT_VERSION'"
272
+ [[ -n "${BUNDLE_VERSION}" ]] && log "Specified bundle version to use: '$BUNDLE_VERSION'"
273
+ [[ -n "${KEYCHAIN_FLAG}" ]] && log "Specified keychain to use: '$KEYCHAIN_PATH'"
274
+ [[ -n "${NEW_FILE}" ]] && log "Output file name: '$NEW_FILE'"
275
+ [[ -n "${USE_APP_ENTITLEMENTS}" ]] && log "Extract app entitlements: YES"
276
+ [[ -n "${REMOVE_PLUGINS}" ]] && log "Remove all plugins: YES"
277
+
278
+ # Check that version number option is not clashing with short or bundle version options
279
+ [[ -n "$VERSION_NUMBER" && (-n "$SHORT_VERSION" || -n "$BUNDLE_VERSION") ]] && error "versionNumber option cannot be used in combination with shortVersion or bundleVersion options"
280
+
281
+ # Check that --use-app-entitlements and -e, --entitlements are not used at the same time
282
+ [[ -n "${USE_APP_ENTITLEMENTS}" && -n ${ENTITLEMENTS} ]] && error "--use-app-entitlements option cannot be used in combination with -e, --entitlements option."
283
+
284
+ # Check output file name
285
+ if [ -z "$NEW_FILE" ]; then
286
+ error "Output file name required"
287
+ fi
288
+
289
+ if [[ "${#RAW_PROVISIONS[*]}" == "0" ]]; then
290
+ error "-p 'xxxx.mobileprovision' argument is required"
291
+ fi
292
+
293
+ # Check for and remove the temporary directory if it already exists
294
+ if [ -d "$TEMP_DIR" ]; then
295
+ log "Removing previous temporary directory: '$TEMP_DIR'"
296
+ rm -Rf "$TEMP_DIR"
297
+ fi
298
+
299
+ filename=$(basename "$ORIGINAL_FILE")
300
+ extension="${filename##*.}"
301
+ filename="${filename%.*}"
302
+
303
+ # Check if the supplied file is an ipa or an app file
304
+ if [ "${extension}" = "ipa" ]; then
305
+ # Unzip the old ipa quietly
306
+ unzip -q "$ORIGINAL_FILE" -d $TEMP_DIR
307
+ checkStatus
308
+ elif [ "${extension}" = "app" ]; then
309
+ # Copy the app file into an ipa-like structure
310
+ mkdir -p "$TEMP_DIR/Payload"
311
+ cp -Rf "${ORIGINAL_FILE}" "$TEMP_DIR/Payload/${filename}.app"
312
+ checkStatus
313
+ else
314
+ error "Error: Only can resign .app files and .ipa files."
315
+ fi
316
+
317
+ # check the keychain
318
+ if [ "${KEYCHAIN}" != "" ]; then
319
+ security list-keychains -s "$KEYCHAIN"
320
+ security unlock "$KEYCHAIN"
321
+ security default-keychain -s "$KEYCHAIN"
322
+ fi
323
+
324
+ # Set the app name
325
+ # In Payload directory may be another file except .app file, such as StoreKit folder.
326
+ # Search the first .app file within the Payload directory
327
+ # shellcheck disable=SC2010
328
+ APP_NAME=$(ls "$TEMP_DIR/Payload/" | grep ".app$" | head -1)
329
+
330
+ # Make sure that PATH includes the location of the PlistBuddy helper tool as its location is not standard
331
+ export PATH=$PATH:/usr/libexec
332
+
333
+ # Test whether two bundle identifiers match
334
+ # The first one may contain the wildcard character '*', in which case pattern matching will be used unless the third parameter is "STRICT"
335
+ function does_bundle_id_match {
336
+
337
+ # shellcheck disable=SC2049
338
+ if [[ "$1" == "$2" ]]; then
339
+ return 0
340
+ elif [[ "$3" != STRICT && "$1" =~ \* ]]; then
341
+ local PATTERN0="${1//\./\\.}" # com.example.* -> com\.example\.*
342
+ local PATTERN1="${PATTERN0//\*/.*}" # com\.example\.* -> com\.example\..*
343
+ if [[ "$2" =~ ^$PATTERN1$ ]]; then
344
+ return 0
345
+ fi
346
+ fi
347
+
348
+ return 1
349
+ }
350
+
351
+ # Find the provisioning profile for a given bundle identifier
352
+ function provision_for_bundle_id {
353
+
354
+ for ARG in "${PROVISIONS_BY_ID[@]}"; do
355
+ if does_bundle_id_match "${ARG%%=*}" "$1" "$2"; then
356
+ echo "${ARG#*=}"
357
+ break
358
+ fi
359
+ done
360
+ }
361
+
362
+ # Find the bundle identifier contained inside a provisioning profile
363
+ function bundle_id_for_provision {
364
+
365
+ local FULL_BUNDLE_ID=$(PlistBuddy -c 'Print :Entitlements:application-identifier' /dev/stdin <<< "$(security cms -D -i "$1")")
366
+ checkStatus
367
+ echo "${FULL_BUNDLE_ID#*.}"
368
+ }
369
+
370
+ # Add given provisioning profile and bundle identifier to the search list
371
+ function add_provision_for_bundle_id {
372
+
373
+ local PROVISION="$1"
374
+ local BUNDLE_ID="$2"
375
+
376
+ local CURRENT_PROVISION=$(provision_for_bundle_id "$BUNDLE_ID" STRICT)
377
+
378
+ if [[ "$CURRENT_PROVISION" != "" && "$CURRENT_PROVISION" != "$PROVISION" ]]; then
379
+ error "Conflicting provisioning profiles '$PROVISION' and '$CURRENT_PROVISION' for bundle identifier '$BUNDLE_ID'."
380
+ fi
381
+
382
+ PROVISIONS_BY_ID+=("$BUNDLE_ID=$PROVISION")
383
+ }
384
+
385
+ # Add given provisioning profile to the search list
386
+ function add_provision {
387
+
388
+ local PROVISION="$1"
389
+
390
+ if [[ "$1" =~ .+=.+ ]]; then
391
+ PROVISION="${1#*=}"
392
+ add_provision_for_bundle_id "$PROVISION" "${1%%=*}"
393
+ elif [[ "$DEFAULT_PROVISION" == "" ]]; then
394
+ DEFAULT_PROVISION="$PROVISION"
395
+ fi
396
+
397
+ if [[ ! -e "$PROVISION" ]]; then
398
+ error "Provisioning profile '$PROVISION' file does not exist"
399
+ fi
400
+
401
+ local BUNDLE_ID=$(bundle_id_for_provision "$PROVISION")
402
+ add_provision_for_bundle_id "$PROVISION" "$BUNDLE_ID"
403
+ }
404
+
405
+ # Load bundle identifiers from provisioning profiles
406
+ for ARG in "${RAW_PROVISIONS[@]}"; do
407
+ add_provision "$ARG"
408
+ done
409
+
410
+ # Resign the given application
411
+ function resign {
412
+
413
+ local APP_PATH="$1"
414
+ local NESTED="$2"
415
+ local BUNDLE_IDENTIFIER="$BUNDLE_IDENTIFIER"
416
+ local NEW_PROVISION="$NEW_PROVISION"
417
+ local APP_IDENTIFIER_PREFIX=""
418
+ local TEAM_IDENTIFIER=""
419
+
420
+ if [[ "$NESTED" == NESTED ]]; then
421
+ # Ignore bundle identifier for nested applications
422
+ BUNDLE_IDENTIFIER=""
423
+ fi
424
+
425
+ # Make sure that the Info.plist file is where we expect it
426
+ if [ ! -e "$APP_PATH/Info.plist" ]; then
427
+ error "Expected file does not exist: '$APP_PATH/Info.plist'"
428
+ fi
429
+
430
+ # Make a copy of old Info.plist, it will come handy later to extract some old values
431
+ cp -f "$APP_PATH/Info.plist" "$TEMP_DIR/oldInfo.plist"
432
+
433
+ # Read in current values from the app
434
+ local CURRENT_NAME=$(PlistBuddy -c "Print :CFBundleDisplayName" "$APP_PATH/Info.plist")
435
+ local CURRENT_BUNDLE_IDENTIFIER=$(PlistBuddy -c "Print :CFBundleIdentifier" "$APP_PATH/Info.plist")
436
+ local NEW_PROVISION=$(provision_for_bundle_id "${BUNDLE_IDENTIFIER:-$CURRENT_BUNDLE_IDENTIFIER}")
437
+
438
+ if [[ "$NEW_PROVISION" == "" && "$NESTED" != NESTED ]]; then
439
+ NEW_PROVISION="$DEFAULT_PROVISION"
440
+ fi
441
+
442
+ if [[ "$NEW_PROVISION" == "" ]]; then
443
+ if [[ "$NESTED" == NESTED ]]; then
444
+ warning "No provisioning profile for nested application: '$APP_PATH' with bundle identifier '${BUNDLE_IDENTIFIER:-$CURRENT_BUNDLE_IDENTIFIER}'"
445
+ else
446
+ warning "No provisioning profile for application: '$APP_PATH' with bundle identifier '${BUNDLE_IDENTIFIER:-$CURRENT_BUNDLE_IDENTIFIER}'"
447
+ fi
448
+ error "Use the -p option (example: -p com.example.app=xxxx.mobileprovision)"
449
+ fi
450
+
451
+ local PROVISION_BUNDLE_IDENTIFIER=$(bundle_id_for_provision "$NEW_PROVISION")
452
+
453
+ # Use provisioning profile's bundle identifier
454
+ if [ "$BUNDLE_IDENTIFIER" == "" ]; then
455
+ # shellcheck disable=SC2049
456
+ if [[ "$PROVISION_BUNDLE_IDENTIFIER" =~ \* ]]; then
457
+ log "Bundle Identifier contains a *, using the current bundle identifier"
458
+ BUNDLE_IDENTIFIER="$CURRENT_BUNDLE_IDENTIFIER"
459
+ else
460
+ BUNDLE_IDENTIFIER="$PROVISION_BUNDLE_IDENTIFIER"
461
+ fi
462
+ fi
463
+
464
+ if ! does_bundle_id_match "$PROVISION_BUNDLE_IDENTIFIER" "$BUNDLE_IDENTIFIER"; then
465
+ error "Bundle Identifier '$PROVISION_BUNDLE_IDENTIFIER' in provisioning profile '$NEW_PROVISION' does not match the Bundle Identifier '$BUNDLE_IDENTIFIER' for application '$APP_PATH'."
466
+ fi
467
+
468
+ log "Current bundle identifier is: '$CURRENT_BUNDLE_IDENTIFIER'"
469
+ log "New bundle identifier will be: '$BUNDLE_IDENTIFIER'"
470
+
471
+ # Update the CFBundleDisplayName property in the Info.plist if a new name has been provided
472
+ if [ "${DISPLAY_NAME}" != "" ]; then
473
+ if [ "${DISPLAY_NAME}" != "${CURRENT_NAME}" ]; then
474
+ log "Changing display name from '$CURRENT_NAME' to '$DISPLAY_NAME'"
475
+ PlistBuddy -c "Set :CFBundleDisplayName $DISPLAY_NAME" "$APP_PATH/Info.plist"
476
+ fi
477
+ fi
478
+
479
+ # Replace the embedded mobile provisioning profile
480
+ log "Validating the new provisioning profile: $NEW_PROVISION"
481
+ security cms -D -i "$NEW_PROVISION" > "$TEMP_DIR/profile.plist"
482
+ checkStatus
483
+
484
+ APP_IDENTIFIER_PREFIX=$(PlistBuddy -c "Print :Entitlements:application-identifier" "$TEMP_DIR/profile.plist" | grep -E '^[A-Z0-9]*' -o | tr -d '\n')
485
+ if [ "$APP_IDENTIFIER_PREFIX" == "" ];
486
+ then
487
+ APP_IDENTIFIER_PREFIX=$(PlistBuddy -c "Print :ApplicationIdentifierPrefix:0" "$TEMP_DIR/profile.plist")
488
+ if [ "$APP_IDENTIFIER_PREFIX" == "" ]; then
489
+ error "Failed to extract any app identifier prefix from '$NEW_PROVISION'"
490
+ else
491
+ warning "WARNING: extracted an app identifier prefix '$APP_IDENTIFIER_PREFIX' from '$NEW_PROVISION', but it was not found in the profile's entitlements"
492
+ fi
493
+ else
494
+ log "Profile app identifier prefix is '$APP_IDENTIFIER_PREFIX'"
495
+ fi
496
+
497
+ # Set new app identifier prefix if such entry exists in plist file
498
+ PlistBuddy -c "Set :AppIdentifierPrefix $APP_IDENTIFIER_PREFIX." "$APP_PATH/Info.plist" 2>/dev/null
499
+
500
+ TEAM_IDENTIFIER=$(PlistBuddy -c "Print :Entitlements:com.apple.developer.team-identifier" "$TEMP_DIR/profile.plist" | tr -d '\n')
501
+ if [ "$TEAM_IDENTIFIER" == "" ]; then
502
+ TEAM_IDENTIFIER=$(PlistBuddy -c "Print :TeamIdentifier:0" "$TEMP_DIR/profile.plist")
503
+ if [ "$TEAM_IDENTIFIER" == "" ]; then
504
+ warning "Failed to extract team identifier from '$NEW_PROVISION', resigned ipa may fail on iOS 8 and higher"
505
+ else
506
+ warning "WARNING: extracted a team identifier '$TEAM_IDENTIFIER' from '$NEW_PROVISION', but it was not found in the profile's entitlements, resigned ipa may fail on iOS 8 and higher"
507
+ fi
508
+ else
509
+ log "Profile team identifier is '$TEAM_IDENTIFIER'"
510
+ fi
511
+
512
+ # Make a copy of old embedded provisioning profile for further use
513
+ cp -f "$APP_PATH/embedded.mobileprovision" "$TEMP_DIR/old-embedded.mobileprovision"
514
+
515
+ # Replace embedded provisioning profile with new file
516
+ cp -f "$NEW_PROVISION" "$APP_PATH/embedded.mobileprovision"
517
+
518
+ #if the current bundle identifier is different from the new one in the provisioning profile, then change it.
519
+ if [ "$CURRENT_BUNDLE_IDENTIFIER" != "$BUNDLE_IDENTIFIER" ]; then
520
+ log "Updating the bundle identifier from '$CURRENT_BUNDLE_IDENTIFIER' to '$BUNDLE_IDENTIFIER'"
521
+ PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_IDENTIFIER" "$APP_PATH/Info.plist"
522
+ checkStatus
523
+ fi
524
+
525
+ # Update the version number properties in the Info.plist if a version number has been provided
526
+ if [ "$VERSION_NUMBER" != "" ]; then
527
+ CURRENT_VERSION_NUMBER=$(PlistBuddy -c "Print :CFBundleVersion" "$APP_PATH/Info.plist")
528
+ if [ "$VERSION_NUMBER" != "$CURRENT_VERSION_NUMBER" ]; then
529
+ log "Updating the version from '$CURRENT_VERSION_NUMBER' to '$VERSION_NUMBER'"
530
+ PlistBuddy -c "Set :CFBundleVersion $VERSION_NUMBER" "$APP_PATH/Info.plist"
531
+ PlistBuddy -c "Set :CFBundleShortVersionString $VERSION_NUMBER" "$APP_PATH/Info.plist"
532
+ fi
533
+ fi
534
+
535
+ # Update short version string in the Info.plist if provided
536
+ if [[ -n "$SHORT_VERSION" ]]; then
537
+ CURRENT_VALUE="$(PlistBuddy -c "Print :CFBundleShortVersionString" "$APP_PATH/Info.plist")"
538
+ # Even if the old value is same - just update, less code, less debugging
539
+ log "Updating the short version string (CFBundleShortVersionString) from '$CURRENT_VALUE' to '$SHORT_VERSION'"
540
+ PlistBuddy -c "Set :CFBundleShortVersionString $SHORT_VERSION" "$APP_PATH/Info.plist"
541
+ fi
542
+
543
+ # Update bundle version in the Info.plist if provided
544
+ if [[ -n "$BUNDLE_VERSION" ]]; then
545
+ CURRENT_VALUE="$(PlistBuddy -c "Print :CFBundleVersion" "$APP_PATH/Info.plist")"
546
+ # Even if the old value is same - just update, less code, less debugging
547
+ log "Updating the bundle version (CFBundleVersion) from '$CURRENT_VALUE' to '$BUNDLE_VERSION'"
548
+ PlistBuddy -c "Set :CFBundleVersion $BUNDLE_VERSION" "$APP_PATH/Info.plist"
549
+ fi
550
+
551
+ # Check for and resign OnDemandResource folders
552
+ ODR_DIR="$(dirname "$APP_PATH")/OnDemandResources"
553
+ if [ -d "$ODR_DIR" ]; then
554
+ for assetpack in "$ODR_DIR"/*
555
+ do
556
+ if [[ "$assetpack" == *.assetpack ]]; then
557
+ rm -rf $assetpack/_CodeSignature
558
+ /usr/bin/codesign ${VERBOSE} --generate-entitlement-der ${KEYCHAIN_FLAG} -f -s "$CERTIFICATE" "$assetpack"
559
+ checkStatus
560
+ else
561
+ log "Ignoring non-assetpack: $assetpack"
562
+ fi
563
+ done
564
+ fi
565
+
566
+ # Check for and resign any embedded frameworks (new feature for iOS 8 and above apps)
567
+ FRAMEWORKS_DIR="$APP_PATH/Frameworks"
568
+ if [ -d "$FRAMEWORKS_DIR" ]; then
569
+ if [ "$TEAM_IDENTIFIER" == "" ]; then
570
+ error "ERROR: embedded frameworks detected, re-signing iOS 8 (or higher) applications wihout a team identifier in the certificate/profile does not work"
571
+ fi
572
+
573
+ log "Resigning embedded frameworks using certificate: '$CERTIFICATE'"
574
+ for framework in "$FRAMEWORKS_DIR"/*
575
+ do
576
+ if [[ "$framework" == *.framework || "$framework" == *.dylib ]]; then
577
+ log "Resigning '$framework'"
578
+ # Must not qote KEYCHAIN_FLAG because it needs to be unwrapped and passed to codesign with spaces
579
+ # shellcheck disable=SC2086
580
+ /usr/bin/codesign ${VERBOSE} --generate-entitlement-der ${KEYCHAIN_FLAG} -f -s "$CERTIFICATE" "$framework"
581
+ checkStatus
582
+ else
583
+ log "Ignoring non-framework: $framework"
584
+ fi
585
+ done
586
+ fi
587
+
588
+ # Check for and update bundle identifiers for extensions and associated nested apps
589
+ log "Fixing nested app and extension references"
590
+ for key in "${NESTED_APP_REFERENCE_KEYS[@]}"; do
591
+ # Check if Info.plist has a reference to another app or extension
592
+ REF_BUNDLE_ID=$(PlistBuddy -c "Print ${key}" "$APP_PATH/Info.plist" 2>/dev/null)
593
+ if [ -n "$REF_BUNDLE_ID" ]; then
594
+ # Found a reference bundle id, now get the corresponding provisioning profile for this bundle id
595
+ REF_PROVISION=$(provision_for_bundle_id "$REF_BUNDLE_ID")
596
+ # Map to the new bundle id
597
+ NEW_REF_BUNDLE_ID=$(bundle_id_for_provision "$REF_PROVISION")
598
+ # Change if not the same and if doesn't contain wildcard
599
+ # shellcheck disable=SC2049
600
+ if [[ "$REF_BUNDLE_ID" != "$NEW_REF_BUNDLE_ID" ]] && ! [[ "$NEW_REF_BUNDLE_ID" =~ \* ]]; then
601
+ log "Updating nested app or extension reference for ${key} key from ${REF_BUNDLE_ID} to ${NEW_REF_BUNDLE_ID}"
602
+ PlistBuddy -c "Set ${key} $NEW_REF_BUNDLE_ID" "$APP_PATH/Info.plist"
603
+ fi
604
+ fi
605
+ done
606
+
607
+ if [ "$ENTITLEMENTS" != "" ]; then
608
+ if [ -n "$APP_IDENTIFIER_PREFIX" ]; then
609
+ # sanity check the 'application-identifier' is present in the provided entitlements and matches the provisioning profile value
610
+ ENTITLEMENTS_APP_ID_PREFIX=$(PlistBuddy -c "Print :application-identifier" "$ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n')
611
+ if [ "$ENTITLEMENTS_APP_ID_PREFIX" == "" ]; then
612
+ error "Provided entitlements file is missing a value for the required 'application-identifier' key"
613
+ elif [ "$ENTITLEMENTS_APP_ID_PREFIX" != "$APP_IDENTIFIER_PREFIX" ]; then
614
+ error "Provided entitlements file's app identifier prefix value '$ENTITLEMENTS_APP_ID_PREFIX' does not match the provided provisioning profile's value '$APP_IDENTIFIER_PREFIX'"
615
+ fi
616
+ fi
617
+
618
+ if [ -n "$TEAM_IDENTIFIER" ]; then
619
+ # sanity check the 'com.apple.developer.team-identifier' is present in the provided entitlements and matches the provisioning profile value
620
+ ENTITLEMENTS_TEAM_IDENTIFIER=$(PlistBuddy -c "Print :com.apple.developer.team-identifier" "$ENTITLEMENTS" | tr -d '\n')
621
+ if [ "$ENTITLEMENTS_TEAM_IDENTIFIER" == "" ]; then
622
+ error "Provided entitlements file is missing a value for the required 'com.apple.developer.team-identifier' key"
623
+ elif [ "$ENTITLEMENTS_TEAM_IDENTIFIER" != "$TEAM_IDENTIFIER" ]; then
624
+ error "Provided entitlements file's 'com.apple.developer.team-identifier' '$ENTITLEMENTS_TEAM_IDENTIFIER' does not match the provided provisioning profile's value '$TEAM_IDENTIFIER'"
625
+ fi
626
+ fi
627
+
628
+ log "Resigning application using certificate: '$CERTIFICATE'"
629
+ log "and entitlements: $ENTITLEMENTS"
630
+ if [[ "${XCODE_VERSION/.*/}" -lt 10 ]]; then
631
+ log "Creating an archived-expanded-entitlements.xcent file for Xcode 9 builds or earlier"
632
+ cp -f "$ENTITLEMENTS" "$APP_PATH/archived-expanded-entitlements.xcent"
633
+ fi
634
+ /usr/bin/codesign ${VERBOSE} --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$ENTITLEMENTS" "$APP_PATH"
635
+ checkStatus
636
+ elif [[ -n "${USE_APP_ENTITLEMENTS}" ]]; then
637
+ # Extract entitlements from provisioning profile and from the app binary
638
+ # then combine them together
639
+
640
+ log "Extracting entitlements from provisioning profile"
641
+ PROFILE_ENTITLEMENTS="$TEMP_DIR/profileEntitlements"
642
+ PlistBuddy -x -c "Print Entitlements" "$TEMP_DIR/profile.plist" > "$PROFILE_ENTITLEMENTS"
643
+ checkStatus
644
+
645
+ log "Extracting entitlements from the app"
646
+ APP_ENTITLEMENTS="$TEMP_DIR/appEntitlements"
647
+ /usr/bin/codesign -d --entitlements :"$APP_ENTITLEMENTS" "$APP_PATH"
648
+ checkStatus
649
+
650
+ log "\nApp entitlements for ${APP_PATH}:"
651
+ log "$(cat "$APP_ENTITLEMENTS")"
652
+
653
+ # Get the old and new app identifier (prefix)
654
+ APP_ID_KEY="application-identifier"
655
+ # Extract just the identifier from the value
656
+ # Use the fact that we are after some identifier, which is always at the start of the string
657
+ OLD_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$APP_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n')
658
+ NEW_APP_ID=$(PlistBuddy -c "Print $APP_ID_KEY" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n')
659
+
660
+ # Get the old and the new team ID
661
+ # Old team ID is not part of app entitlements, have to get it from old embedded provisioning profile
662
+ security cms -D -i "$TEMP_DIR/old-embedded.mobileprovision" > "$TEMP_DIR/old-embedded-profile.plist"
663
+ OLD_TEAM_ID=$(PlistBuddy -c "Print :TeamIdentifier:0" "$TEMP_DIR/old-embedded-profile.plist")
664
+ # New team ID is part of profile entitlements
665
+ NEW_TEAM_ID=$(PlistBuddy -c "Print com.apple.developer.team-identifier" "$PROFILE_ENTITLEMENTS" | grep -E '^[A-Z0-9]*' -o | tr -d '\n')
666
+
667
+ log "Patching profile entitlements with values from app entitlements"
668
+ PATCHED_ENTITLEMENTS="$TEMP_DIR/patchedEntitlements"
669
+ # Start with using what comes in provisioning profile entitlements before patching
670
+ cp -f "$PROFILE_ENTITLEMENTS" "$PATCHED_ENTITLEMENTS"
671
+
672
+ log "Removing denylisted keys from patched profile"
673
+ # See https://github.com/facebook/buck/issues/798 and https://github.com/facebook/buck/pull/802/files
674
+
675
+ # Update in https://github.com/facebook/buck/commit/99c0fbc3ab5ecf04d186913374f660683deccdef
676
+ # Update in https://github.com/facebook/buck/commit/36db188da9f6acbb9df419dc1904315ab00c4e19
677
+
678
+ # Buck changes referenced above are not self-explanatory and do not seem exhaustive or up-to-date
679
+ # Comments below explain the rules applied to each key in order to make realignment with future Xcode export logic easier
680
+ DENYLISTED_KEYS=(\
681
+ # PP list identifiers inconsistent with app-defined ones and this key does not seem to appear in IPA entitlements, so ignore it
682
+ "com.apple.developer.icloud-container-development-container-identifiers" \
683
+ # This key has an invalid generic value in PP (actual value is set by Xcode during export), see dedicated processing a few blocks below
684
+ "com.apple.developer.icloud-container-environment" \
685
+ # PP enable all available services and not app-defined ones, must use App entitlements value
686
+ "com.apple.developer.icloud-services" \
687
+ # Was already denylisted in previous version, but has someone ever seen this key in a PP?
688
+ "com.apple.developer.restricted-resource-mode" \
689
+ # If actually used by the App, this value will be set in its entitlements
690
+ "com.apple.developer.nfc.readersession.formats" \
691
+ # If actually used by the App, this value will be set in its entitlements
692
+ "com.apple.developer.siri" \
693
+ # PP define a generic TeamID.* identifier and not the app-defined one, must use App entitlements value
694
+ "com.apple.developer.ubiquity-kvstore-identifier" \
695
+ # If actually used by the App, this value will be set in its entitlements
696
+ "inter-app-audio" \
697
+ # PP define a generic TeamID.* identifier and not the app-defined one, must use App entitlements value
698
+ "keychain-access-groups" \
699
+ # If actually used by the App, this value will be set in its entitlements
700
+ "com.apple.developer.homekit" \
701
+ # If actually used by the App, this value will be set in its entitlements
702
+ "com.apple.developer.healthkit" \
703
+ # If actually used by the App, this value will be set in its entitlements
704
+ "com.apple.developer.healthkit.access" \
705
+ # If actually used by the App, this value will be set in its entitlements
706
+ "com.apple.developer.networking.vpn.api" \
707
+ # If actually used by the App, this value will be set in its entitlements
708
+ "com.apple.developer.networking.HotspotConfiguration" \
709
+ # PP list all available extensions and not app-defined ones, must use App entitlements value
710
+ "com.apple.developer.networking.networkextension" \
711
+ # If actually used by the App, this value will be set in its entitlements
712
+ "com.apple.developer.networking.multipath" \
713
+ # PP enable all domains via a non-AppStore-compliant '*' value, must use App entitlements value
714
+ "com.apple.developer.associated-domains" \
715
+ # If actually used by the App, this value will be set in its entitlements
716
+ "com.apple.developer.default-data-protection" \
717
+ # Was already denylisted in previous version, seems to be an artifact from an old Xcode release
718
+ "com.apple.developer.maps" \
719
+ # If actually used by the App, this value will be set in its entitlements
720
+ "com.apple.external-accessory.wireless-configuration"
721
+ )
722
+
723
+ # If we change team while resigning, we have no other choice than to use the following entitlements from the PP instead of the App
724
+ # because they are based on unique identifiers (defined in the developer portal) that can't be shared between teams
725
+ if [[ "$OLD_TEAM_ID" != "$NEW_TEAM_ID" ]]; then
726
+ warning "WARNING: Changing team while resigning"
727
+ warning "WARNING: Using these entitlements from the provisioning profile instead of the existing app:"
728
+ warning "WARNING: App Groups, Merchant IDs (Apple Pay In-App Payments), iCloud Containers, Pass Type IDs (Wallet)"
729
+ warning "WARNING: If these capabilities are enabled, make sure AppID and provisioning profile are properly configured"
730
+ # For Pass Types, PP only list a single TeamID.* identifier and not the potential restricted list defined in the existing App
731
+ # 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
732
+ warning "WARNING: Resigned app will allow all pass types from the new team, even if old app only allowed a restricted list"
733
+ else
734
+ DENYLISTED_KEYS+=(\
735
+ "com.apple.security.application-groups" \
736
+ "com.apple.developer.in-app-payments" \
737
+ "com.apple.developer.ubiquity-container-identifiers" \
738
+ "com.apple.developer.icloud-container-identifiers" \
739
+ "com.apple.developer.pass-type-identifiers" \
740
+ )
741
+ fi
742
+
743
+ # Denylisted keys must not be included into new profile, so remove them from patched profile
744
+ for KEY in "${DENYLISTED_KEYS[@]}"; do
745
+ log "Removing denylisted key: $KEY"
746
+ PlistBuddy -c "Delete $KEY" "$PATCHED_ENTITLEMENTS" 2>/dev/null
747
+ done
748
+
749
+ # List of rules for transferring entitlements from app to profile plist
750
+ # The format for each enty is "KEY[|ID_TYPE]"
751
+ # Where KEY is the plist key, e.g. "keychain-access-groups"
752
+ # and ID_TYPE is optional part separated by '|' that specifies what value to patch:
753
+ # TEAM_ID - patch the TeamIdentifierPrefix
754
+ # APP_ID - patch the AppIdentifierPrefix
755
+ # ICLOUD_ENV - patch the target iCloud Environment
756
+ # Patching means replacing old value from app entitlements with new value from provisioning profile
757
+ # For example, for KEY=keychain-access-groups the ID_TYPE=APP_ID
758
+ # Which means that old app ID prefix in keychain-access-groups will be replaced with new app ID prefix
759
+ # There can be only one ID_TYPE specified
760
+ # If entitlements use more than one ID type for single entitlement, then this way of resigning will not work
761
+ # instead an entitlements file must be provided explicitly
762
+ ENTITLEMENTS_TRANSFER_RULES=(\
763
+ "com.apple.developer.associated-domains" \
764
+ "com.apple.developer.default-data-protection" \
765
+ "com.apple.developer.healthkit" \
766
+ "com.apple.developer.healthkit.access" \
767
+ "com.apple.developer.homekit" \
768
+ "com.apple.developer.icloud-container-environment|ICLOUD_ENV" \
769
+ "com.apple.developer.icloud-services" \
770
+ "com.apple.developer.networking.HotspotConfiguration" \
771
+ "com.apple.developer.networking.multipath" \
772
+ "com.apple.developer.networking.networkextension" \
773
+ "com.apple.developer.networking.vpn.api" \
774
+ "com.apple.developer.nfc.readersession.formats" \
775
+ "com.apple.developer.siri" \
776
+ "com.apple.developer.ubiquity-kvstore-identifier|TEAM_ID" \
777
+ "com.apple.external-accessory.wireless-configuration" \
778
+ "inter-app-audio" \
779
+ "keychain-access-groups|APP_ID" \
780
+ )
781
+
782
+ # If we change team while resigning, we have no other choice than to use the following entitlements from the PP instead of the App
783
+ # because they are based on unique identifiers (defined in the developer portal) that can't be shared between teams
784
+ # If we don't change team while resigning, we should use the following entitlements from the existing App and not from the PP
785
+ if [[ "$OLD_TEAM_ID" == "$NEW_TEAM_ID" ]]; then
786
+ ENTITLEMENTS_TRANSFER_RULES+=(\
787
+ "com.apple.security.application-groups" \
788
+ "com.apple.developer.in-app-payments" \
789
+ "com.apple.developer.ubiquity-container-identifiers" \
790
+ "com.apple.developer.icloud-container-identifiers" \
791
+ "com.apple.developer.pass-type-identifiers|TEAM_ID" \
792
+ )
793
+ fi
794
+
795
+ # Loop over all the entitlement keys that need to be transferred from app entitlements
796
+ for RULE in "${ENTITLEMENTS_TRANSFER_RULES[@]}"; do
797
+ KEY=$(echo "$RULE" | cut -d'|' -f1)
798
+ ID_TYPE=$(echo "$RULE" | cut -d'|' -f2)
799
+
800
+ # Get the entry from app's entitlements
801
+ # Read it with PlistBuddy as XML, then strip the header and <plist></plist> part
802
+ ENTITLEMENTS_VALUE="$(PlistBuddy -x -c "Print $KEY" "$APP_ENTITLEMENTS" 2>/dev/null | tr -d '\n' | /usr/bin/sed -e 's,.*<plist[^>]*>\(.*\)</plist>,\1,g')"
803
+ if [[ -z "$ENTITLEMENTS_VALUE" ]]; then
804
+ log "No value for '$KEY'"
805
+ continue
806
+ fi
807
+
808
+ log "App entitlements value for key '$KEY':"
809
+ log "$ENTITLEMENTS_VALUE"
810
+
811
+ # Patch the ID value if specified
812
+ if [[ "$ID_TYPE" == "APP_ID" ]]; then
813
+ # Replace old value with new value in patched entitlements
814
+ log "Replacing old app ID '$OLD_APP_ID' with new app ID '$NEW_APP_ID'"
815
+ ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_APP_ID/$NEW_APP_ID/g")
816
+ elif [[ "$ID_TYPE" == "TEAM_ID" ]]; then
817
+ # Replace old team identifier with new value
818
+ log "Replacing old team ID '$OLD_TEAM_ID' with new team ID '$NEW_TEAM_ID'"
819
+ ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_TEAM_ID/$NEW_TEAM_ID/g")
820
+ elif [[ "$ID_TYPE" == "ICLOUD_ENV" ]]; then
821
+ # Add specific iCloud Environment key to patched entitlements
822
+ # This value is set by Xcode during export (manually selected for Development and AdHoc, automatically set to Production for Store)
823
+ # Would need an additional dedicated option to specify the iCloud environment to be used (Development or Production)
824
+ # For now, we assume Production is to be used when signing with a Distribution certificate, Development if not
825
+ local certificate_name=$CERTIFICATE
826
+ local sha1_pattern='[0-9A-F]{40}'
827
+
828
+ if [[ "$CERTIFICATE" =~ $sha1_pattern ]]; then
829
+ log "Certificate $CERTIFICATE matches a SHA1 pattern"
830
+ local certificate_matches="$( security find-identity -v -p codesigning | grep -m 1 "$CERTIFICATE" )"
831
+ if [ -n "$certificate_matches" ]; then
832
+ certificate_name="$(/usr/bin/sed -E s/[^\"]+\"\([^\"]+\)\".*/\\1/ <<< $certificate_matches )"
833
+ log "Certificate name: $certificate_name"
834
+ fi
835
+ fi
836
+
837
+ OLD_ICLOUD_ENV=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e 's,<string>\(.*\)</string>,\1,g')
838
+ if [[ "$certificate_name" =~ "Distribution:" ]]; then
839
+ NEW_ICLOUD_ENV="Production"
840
+ else
841
+ NEW_ICLOUD_ENV="Development"
842
+ fi
843
+ log "Replacing iCloud environment '$OLD_ICLOUD_ENV' with '$NEW_ICLOUD_ENV'"
844
+ ENTITLEMENTS_VALUE=$(echo "$ENTITLEMENTS_VALUE" | /usr/bin/sed -e "s/$OLD_ICLOUD_ENV/$NEW_ICLOUD_ENV/g")
845
+ fi
846
+
847
+ # Remove the entry for current key from profisioning profile entitlements (if exists)
848
+ PlistBuddy -c "Delete $KEY" "$PATCHED_ENTITLEMENTS" 2>/dev/null
849
+
850
+ # Add new entry to patched entitlements
851
+ # plutil needs dots in the key path to be escaped (e.g. com\.apple\.security\.application-groups)
852
+ # otherwise it interprets they key path as nested keys
853
+ # TODO: Should be able to replace with echo ${KEY//\./\\\\.} and remove shellcheck disable directive
854
+ # shellcheck disable=SC2001
855
+ PLUTIL_KEY=$(echo "$KEY" | /usr/bin/sed -e 's/\./\\\./g')
856
+ plutil -insert "$PLUTIL_KEY" -xml "$ENTITLEMENTS_VALUE" "$PATCHED_ENTITLEMENTS"
857
+ done
858
+
859
+ # Replace old bundle ID with new bundle ID in patched entitlements
860
+ # Read old bundle ID from the old Info.plist which was saved for this purpose
861
+ OLD_BUNDLE_ID="$(PlistBuddy -c "Print :CFBundleIdentifier" "$TEMP_DIR/oldInfo.plist")"
862
+ NEW_BUNDLE_ID="$(bundle_id_for_provision "$NEW_PROVISION")"
863
+ log "Replacing old bundle ID '$OLD_BUNDLE_ID' with new bundle ID '$NEW_BUNDLE_ID' in patched entitlements"
864
+ # Note: ideally we'd match against the opening <string> tag too, but this isn't possible
865
+ # because $OLD_BUNDLE_ID and $NEW_BUNDLE_ID do not include the team ID prefix which is
866
+ # present in the entitlements file.
867
+ # e.g. <string>AB1GP98Q19.com.example.foo</string>
868
+ # vs
869
+ # com.example.foo
870
+ /usr/bin/sed -i .bak "s!${OLD_BUNDLE_ID}</string>!${NEW_BUNDLE_ID}</string>!g" "$PATCHED_ENTITLEMENTS"
871
+
872
+ log "Resigning application using certificate: '$CERTIFICATE'"
873
+ log "and patched entitlements:"
874
+ log "$(cat "$PATCHED_ENTITLEMENTS")"
875
+ if [[ "${XCODE_VERSION/.*/}" -lt 10 ]]; then
876
+ log "Creating an archived-expanded-entitlements.xcent file for Xcode 9 builds or earlier"
877
+ cp -f "$PATCHED_ENTITLEMENTS" "$APP_PATH/archived-expanded-entitlements.xcent"
878
+ fi
879
+ /usr/bin/codesign ${VERBOSE} --generate-entitlement-der -f -s "$CERTIFICATE" --entitlements "$PATCHED_ENTITLEMENTS" "$APP_PATH"
880
+ checkStatus
881
+ else
882
+ log "Extracting entitlements from provisioning profile"
883
+ PlistBuddy -x -c "Print Entitlements" "$TEMP_DIR/profile.plist" > "$TEMP_DIR/newEntitlements"
884
+ checkStatus
885
+ log "Resigning application using certificate: '$CERTIFICATE'"
886
+ log "and entitlements from provisioning profile: $NEW_PROVISION"
887
+ if [[ "${XCODE_VERSION/.*/}" -lt 10 ]]; then
888
+ log "Creating an archived-expanded-entitlements.xcent file for Xcode 9 builds or earlier"
889
+ cp -- "$TEMP_DIR/newEntitlements" "$APP_PATH/archived-expanded-entitlements.xcent"
890
+ fi
891
+ # Must not qote KEYCHAIN_FLAG because it needs to be unwrapped and passed to codesign with spaces
892
+ # shellcheck disable=SC2086
893
+ /usr/bin/codesign ${VERBOSE} --generate-entitlement-der ${KEYCHAIN_FLAG} -f -s "$CERTIFICATE" --entitlements "$TEMP_DIR/newEntitlements" "$APP_PATH"
894
+ checkStatus
895
+ fi
896
+
897
+ # Remove the temporary files if they were created before generating ipa
898
+ rm -f "$TEMP_DIR/newEntitlements"
899
+ rm -f "$PROFILE_ENTITLEMENTS"
900
+ rm -f "$APP_ENTITLEMENTS"
901
+ rm -f "$PATCHED_ENTITLEMENTS"
902
+ rm -f "$PATCHED_ENTITLEMENTS.bak"
903
+ rm -f "$TEMP_DIR/old-embedded-profile.plist"
904
+ rm -f "$TEMP_DIR/profile.plist"
905
+ rm -f "$TEMP_DIR/old-embedded.mobileprovision"
906
+ rm -f "$TEMP_DIR/oldInfo.plist"
907
+ }
908
+
909
+ # remove all plugins
910
+ if [[ -n "${REMOVE_PLUGINS}" ]]; then
911
+ rm -rf "$TEMP_DIR/Payload/$APP_NAME/Plugins"
912
+ fi
913
+
914
+ # Sign nested applications and app extensions
915
+ while IFS= read -d '' -r app;
916
+ do
917
+ log "Resigning nested application: '$app'"
918
+ resign "$app" NESTED
919
+ done < <(find "$TEMP_DIR/Payload/$APP_NAME" -d -mindepth 1 \( -name "*.app" -or -name "*.appex" \) -print0)
920
+
921
+ # Resign the application
922
+ resign "$TEMP_DIR/Payload/$APP_NAME"
923
+
924
+ # Repackage quietly
925
+ log "Repackaging as $NEW_FILE"
926
+
927
+ # Zip up the contents of the "$TEMP_DIR" folder
928
+ # Navigate to the temporary directory (sending the output to null)
929
+ # Zip all the contents, saving the zip file in the above directory
930
+ # Navigate back to the orignating directory (sending the output to null)
931
+ pushd "$TEMP_DIR" > /dev/null
932
+ # TODO: Fix shellcheck warning and remove directive
933
+ # shellcheck disable=SC2035
934
+ zip -qry "../$TEMP_DIR.ipa" *
935
+ popd > /dev/null
936
+
937
+ # Move the resulting ipa to the target destination
938
+ mv "$TEMP_DIR.ipa" "$NEW_FILE"
939
+
940
+ # Remove the temp directory
941
+ rm -rf "$TEMP_DIR"
942
+
943
+ log "Process complete"