@revopush/react-native-code-push 1.4.0 → 2.5.0-rc.0

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.
Files changed (44) hide show
  1. package/CodePush.js +8 -5
  2. package/CodePush.podspec +9 -0
  3. package/README.md +7 -6
  4. package/android/build.gradle +52 -40
  5. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  6. package/android/gradle/wrapper/gradle-wrapper.properties +3 -1
  7. package/android/gradle.properties +1 -1
  8. package/android/libs/revopush-diff-release-v0.0.1.aar +0 -0
  9. package/android/proguard-rules.pro +1 -1
  10. package/android/settings.gradle +31 -0
  11. package/android/src/main/java/com/microsoft/codepush/react/CodePush.java +8 -4
  12. package/android/src/main/java/com/microsoft/codepush/react/CodePushConstants.java +11 -7
  13. package/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +48 -41
  14. package/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +67 -175
  15. package/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +7 -244
  16. package/android/src/main/java/com/microsoft/codepush/react/CodePushUtils.java +16 -51
  17. package/android/src/main/java/com/microsoft/codepush/react/FileUtils.java +1 -130
  18. package/ios/CodePush/CodePush.h +1 -30
  19. package/ios/CodePush/CodePush.m +23 -7
  20. package/ios/CodePush/CodePushPackage.m +363 -294
  21. package/ios/CodePush/CodePushUpdateUtils.m +77 -28
  22. package/ios/CodePush.xcodeproj/project.pbxproj +0 -18
  23. package/ios/Frameworks/DiffUpdates.xcframework/Info.plist +44 -0
  24. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/DiffUpdates +0 -0
  25. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Headers/DiffUpdates.h +61 -0
  26. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Info.plist +0 -0
  27. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Modules/module.modulemap +6 -0
  28. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/DiffUpdates +0 -0
  29. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Headers/DiffUpdates.h +61 -0
  30. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Info.plist +0 -0
  31. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Modules/module.modulemap +6 -0
  32. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeDirectory +0 -0
  33. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeRequirements +0 -0
  34. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeRequirements-1 +0 -0
  35. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeResources +132 -0
  36. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeSignature +0 -0
  37. package/package.json +2 -2
  38. package/request-fetch-adapter.js +2 -2
  39. package/scripts/generateBundledResourcesHash.js +102 -65
  40. package/android/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java +0 -72
  41. package/ios/CodePush/CodePushDownloadHandler.m +0 -130
  42. package/ios/CodePush/CodePushErrorUtils.m +0 -20
  43. package/ios/CodePush/CodePushUtils.m +0 -9
  44. package/revopush-react-native-code-push-1.4.0-rc1.tgz +0 -0
@@ -5,6 +5,8 @@
5
5
  #import "SSZipArchive.h"
6
6
  #endif
7
7
 
8
+ #import <DiffUpdates/DiffUpdates.h>
9
+
8
10
  @implementation CodePushPackage
9
11
 
10
12
  #pragma mark - Private constants
@@ -31,7 +33,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
31
33
  NSString *downloadedBundle = [NSString stringWithContentsOfURL:urlRequest
32
34
  encoding:NSUTF8StringEncoding
33
35
  error:&error];
34
-
36
+
35
37
  if (error) {
36
38
  CPLog(@"Error downloading from URL %@", remoteBundleUrl);
37
39
  } else {
@@ -51,11 +53,12 @@ static NSString *const UnzippedFolderName = @"unzipped";
51
53
  doneCallback:(void (^)())doneCallback
52
54
  failCallback:(void (^)(NSError *err))failCallback
53
55
  {
56
+ CPLog(@"updatePackage = %@", updatePackage);
54
57
  NSString *newUpdateHash = updatePackage[@"packageHash"];
55
58
  NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash];
56
59
  NSString *newUpdateMetadataPath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateMetadataFileName];
57
60
  NSError *error;
58
-
61
+
59
62
  if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateFolderPath]) {
60
63
  // This removes any stale data in newUpdateFolderPath that could have been left
61
64
  // uncleared due to a crash or error during the download or install process.
@@ -66,282 +69,348 @@ static NSString *const UnzippedFolderName = @"unzipped";
66
69
  withIntermediateDirectories:YES
67
70
  attributes:nil
68
71
  error:&error];
69
-
72
+
70
73
  // Ensure that none of the CodePush updates we store on disk are
71
74
  // ever included in the end users iTunes and/or iCloud backups
72
75
  NSURL *codePushURL = [NSURL fileURLWithPath:[self getCodePushPath]];
73
76
  [codePushURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
74
77
  }
75
-
78
+
76
79
  if (error) {
77
80
  return failCallback(error);
78
81
  }
79
-
82
+
80
83
  NSString *downloadFilePath = [self getDownloadFilePath];
81
84
  NSString *bundleFilePath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateBundleFileName];
82
-
83
- CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc]
84
- init:downloadFilePath
85
- operationQueue:operationQueue
86
- progressCallback:progressCallback
87
- doneCallback:^(BOOL isZip) {
88
- NSError *error = nil;
89
- NSString * unzippedFolderPath = [CodePushPackage getUnzippedFolderPath];
90
- NSMutableDictionary * mutableUpdatePackage = [updatePackage mutableCopy];
91
- if (isZip) {
92
- if ([[NSFileManager defaultManager] fileExistsAtPath:unzippedFolderPath]) {
93
- // This removes any unzipped download data that could have been left
94
- // uncleared due to a crash or error during the download process.
95
- [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath
96
- error:&error];
97
- if (error) {
98
- failCallback(error);
99
- return;
100
- }
101
- }
102
-
103
- NSError *nonFailingError = nil;
104
- [SSZipArchive unzipFileAtPath:downloadFilePath
105
- toDestination:unzippedFolderPath];
106
- [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath
107
- error:&nonFailingError];
108
- if (nonFailingError) {
109
- CPLog(@"Error deleting downloaded file: %@", nonFailingError);
110
- nonFailingError = nil;
111
- }
112
-
113
- NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName];
114
- BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath];
115
-
116
- if (isDiffUpdate) {
117
- // Copy the current package to the new package.
118
- NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];
119
- if (error) {
120
- failCallback(error);
121
- return;
122
- }
123
-
124
- if (currentPackageFolderPath == nil) {
125
- // Currently running the binary version, copy files from the bundled resources
126
- NSString *newUpdateCodePushPath = [newUpdateFolderPath stringByAppendingPathComponent:[CodePushUpdateUtils manifestFolderPrefix]];
127
- [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateCodePushPath
128
- withIntermediateDirectories:YES
129
- attributes:nil
130
- error:&error];
131
- if (error) {
132
- failCallback(error);
133
- return;
134
- }
135
-
136
- [[NSFileManager defaultManager] copyItemAtPath:[CodePush bundleAssetsPath]
137
- toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]]
138
- error:&error];
139
- if (error) {
140
- failCallback(error);
141
- return;
142
- }
143
-
144
- [[NSFileManager defaultManager] copyItemAtPath:[[CodePush binaryBundleURL] path]
145
- toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[[CodePush binaryBundleURL] lastPathComponent]]
146
- error:&error];
147
- if (error) {
148
- failCallback(error);
149
- return;
150
- }
151
- } else {
152
- [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath
153
- toPath:newUpdateFolderPath
154
- error:&error];
155
- if (error) {
156
- failCallback(error);
157
- return;
158
- }
159
- }
160
-
161
- // Delete files mentioned in the manifest.
162
- NSString *manifestContent = [NSString stringWithContentsOfFile:diffManifestFilePath
163
- encoding:NSUTF8StringEncoding
164
- error:&error];
165
- if (error) {
166
- failCallback(error);
167
- return;
168
- }
169
-
170
- NSData *data = [manifestContent dataUsingEncoding:NSUTF8StringEncoding];
171
- NSDictionary *manifestJSON = [NSJSONSerialization JSONObjectWithData:data
172
- options:kNilOptions
173
- error:&error];
174
- NSArray *deletedFiles = manifestJSON[@"deletedFiles"];
175
- for (NSString *deletedFileName in deletedFiles) {
176
- NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName];
177
- if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) {
178
- [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath
179
- error:&error];
180
- if (error) {
181
- failCallback(error);
182
- return;
183
- }
184
- }
185
- }
186
-
187
- [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath
188
- error:&error];
189
- if (error) {
190
- failCallback(error);
191
- return;
192
- }
193
- }
194
-
195
- [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath
196
- destFolder:newUpdateFolderPath
197
- error:&error];
198
- if (error) {
199
- failCallback(error);
200
- return;
201
- }
202
-
203
- [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath
204
- error:&nonFailingError];
205
- if (nonFailingError) {
206
- CPLog(@"Error deleting downloaded file: %@", nonFailingError);
207
- nonFailingError = nil;
208
- }
209
-
210
- NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath
211
- expectedFileName:expectedBundleFileName
212
- error:&error];
213
-
214
- if (error) {
215
- failCallback(error);
216
- return;
217
- }
218
-
219
- if (relativeBundlePath) {
220
- [mutableUpdatePackage setValue:relativeBundlePath forKey:RelativeBundlePathKey];
221
- } else {
222
- NSString *errorMessage = [NSString stringWithFormat:@"Update is invalid - A JS bundle file named \"%@\" could not be found within the downloaded contents. Please ensure that your app is syncing with the correct deployment and that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.", expectedBundleFileName];
223
-
224
- error = [CodePushErrorUtils errorWithMessage:errorMessage];
225
-
226
- failCallback(error);
227
- return;
228
- }
229
-
230
- if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) {
231
- [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath
232
- error:&error];
233
- if (error) {
234
- failCallback(error);
235
- return;
236
- }
237
- }
238
-
239
- CPLog((isDiffUpdate) ? @"Applying diff update." : @"Applying full update.");
240
-
241
- BOOL isSignatureVerificationEnabled = (publicKey != nil);
242
-
243
- NSString *signatureFilePath = [CodePushUpdateUtils getSignatureFilePath:newUpdateFolderPath];
244
- BOOL isSignatureAppearedInBundle = [[NSFileManager defaultManager] fileExistsAtPath:signatureFilePath];
245
-
246
- if (isSignatureVerificationEnabled) {
247
- if (isSignatureAppearedInBundle) {
248
- if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
249
- expectedHash:newUpdateHash
250
- error:&error]) {
251
- CPLog(@"The update contents failed the data integrity check.");
252
- if (!error) {
253
- error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."];
254
- }
255
-
256
- failCallback(error);
257
- return;
258
- } else {
259
- CPLog(@"The update contents succeeded the data integrity check.");
260
- }
261
- BOOL isSignatureValid = [CodePushUpdateUtils verifyUpdateSignatureFor:newUpdateFolderPath
262
- expectedHash:newUpdateHash
263
- withPublicKey:publicKey
264
- error:&error];
265
- if (!isSignatureValid) {
266
- CPLog(@"The update contents failed code signing check.");
267
- if (!error) {
268
- error = [CodePushErrorUtils errorWithMessage:@"The update contents failed code signing check."];
269
- }
270
- failCallback(error);
271
- return;
272
- } else {
273
- CPLog(@"The update contents succeeded the code signing check.");
274
- }
275
- } else {
276
- error = [CodePushErrorUtils errorWithMessage:
277
- @"Error! Public key was provided but there is no JWT signature within app bundle to verify " \
278
- "Possible reasons, why that might happen: \n" \
279
- "1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\n" \
280
- "2. You've been released CodePush bundle update without providing --privateKeyPath option."];
281
- failCallback(error);
282
- return;
283
- }
284
-
285
- } else {
286
- BOOL needToVerifyHash;
287
- if (isSignatureAppearedInBundle) {
288
- CPLog(@"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed" \
289
- " because there is no public key configured. " \
290
- "Please ensure that public key is properly configured within your application.");
291
- needToVerifyHash = true;
292
- } else {
293
- needToVerifyHash = isDiffUpdate;
294
- }
295
- if(needToVerifyHash){
296
- if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
297
- expectedHash:newUpdateHash
298
- error:&error]) {
299
- CPLog(@"The update contents failed the data integrity check.");
300
- if (!error) {
301
- error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."];
302
- }
303
-
304
- failCallback(error);
305
- return;
306
- } else {
307
- CPLog(@"The update contents succeeded the data integrity check.");
308
- }
309
- }
310
- }
311
- } else {
312
- [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath
313
- withIntermediateDirectories:YES
314
- attributes:nil
315
- error:&error];
316
- [[NSFileManager defaultManager] moveItemAtPath:downloadFilePath
317
- toPath:bundleFilePath
318
- error:&error];
319
- if (error) {
320
- failCallback(error);
321
- return;
322
- }
323
- }
324
-
325
- NSData *updateSerializedData = [NSJSONSerialization dataWithJSONObject:mutableUpdatePackage
326
- options:0
327
- error:&error];
328
- NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData
329
- encoding:NSUTF8StringEncoding];
330
-
331
- [packageJsonString writeToFile:newUpdateMetadataPath
332
- atomically:YES
333
- encoding:NSUTF8StringEncoding
334
- error:&error];
335
- if (error) {
336
- failCallback(error);
337
- } else {
338
- doneCallback();
339
- }
340
- }
341
-
342
- failCallback:failCallback];
343
-
344
- [downloadHandler download:updatePackage[@"downloadUrl"]];
85
+
86
+ id rawDiff = updatePackage[@"bundleDiffBlobUrl"] ?: updatePackage[@"bundle_diff_blob_url"];
87
+ NSString *bundleDiffUrl = [rawDiff isKindOfClass:NSString.class] ? (NSString *)rawDiff : nil;
88
+ NSString *assetsUrl = updatePackage[@"assetDownloadUrl"] ?: updatePackage[@"asset_download_url"];
89
+ NSString *assetHash = updatePackage[@"assetHash"] ?: updatePackage[@"asset_hash"];
90
+ NSString *singleUrl = updatePackage[@"downloadUrl"] ?: updatePackage[@"download_url"];
91
+
92
+ __block BOOL cameFromDiffHandler = (bundleDiffUrl.length > 0);
93
+
94
+
95
+ void (^commonDone)(BOOL) = ^(BOOL isZip) {
96
+ NSError *error = nil;
97
+ NSString * unzippedFolderPath = [CodePushPackage getUnzippedFolderPath];
98
+ NSMutableDictionary * mutableUpdatePackage = [updatePackage mutableCopy];
99
+ if (isZip) {
100
+ if ([[NSFileManager defaultManager] fileExistsAtPath:unzippedFolderPath]) {
101
+ // This removes any unzipped download data that could have been left
102
+ // uncleared due to a crash or error during the download process.
103
+ [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath
104
+ error:&error];
105
+ if (error) {
106
+ failCallback(error);
107
+ return;
108
+ }
109
+ }
110
+
111
+ NSError *nonFailingError = nil;
112
+ [SSZipArchive unzipFileAtPath:downloadFilePath
113
+ toDestination:unzippedFolderPath];
114
+ [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath
115
+ error:&nonFailingError];
116
+ if (nonFailingError) {
117
+ CPLog(@"Error deleting downloaded file: %@", nonFailingError);
118
+ nonFailingError = nil;
119
+ }
120
+
121
+ NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName];
122
+ BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath];
123
+
124
+ if (isDiffUpdate) {
125
+ // Copy the current package to the new package.
126
+ NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];
127
+ if (error) {
128
+ failCallback(error);
129
+ return;
130
+ }
131
+
132
+ if (currentPackageFolderPath == nil) {
133
+ // Currently running the binary version, copy files from the bundled resources
134
+ NSString *newUpdateCodePushPath = [newUpdateFolderPath stringByAppendingPathComponent:[CodePushUpdateUtils manifestFolderPrefix]];
135
+ [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateCodePushPath
136
+ withIntermediateDirectories:YES
137
+ attributes:nil
138
+ error:&error];
139
+ if (error) {
140
+ failCallback(error);
141
+ return;
142
+ }
143
+
144
+ [[NSFileManager defaultManager] copyItemAtPath:[CodePush bundleAssetsPath]
145
+ toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]]
146
+ error:&error];
147
+ if (error) {
148
+ failCallback(error);
149
+ return;
150
+ }
151
+
152
+ [[NSFileManager defaultManager] copyItemAtPath:[[CodePush binaryBundleURL] path]
153
+ toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[[CodePush binaryBundleURL] lastPathComponent]]
154
+ error:&error];
155
+ if (error) {
156
+ failCallback(error);
157
+ return;
158
+ }
159
+ } else {
160
+ [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath
161
+ toPath:newUpdateFolderPath
162
+ error:&error];
163
+ if (error) {
164
+ failCallback(error);
165
+ return;
166
+ }
167
+ }
168
+
169
+ // Delete files mentioned in the manifest.
170
+ NSString *manifestContent = [NSString stringWithContentsOfFile:diffManifestFilePath
171
+ encoding:NSUTF8StringEncoding
172
+ error:&error];
173
+ if (error) {
174
+ failCallback(error);
175
+ return;
176
+ }
177
+
178
+ NSData *data = [manifestContent dataUsingEncoding:NSUTF8StringEncoding];
179
+ NSDictionary *manifestJSON = [NSJSONSerialization JSONObjectWithData:data
180
+ options:kNilOptions
181
+ error:&error];
182
+ NSArray *deletedFiles = manifestJSON[@"deletedFiles"];
183
+ for (NSString *deletedFileName in deletedFiles) {
184
+ NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName];
185
+ if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) {
186
+ [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath
187
+ error:&error];
188
+ if (error) {
189
+ failCallback(error);
190
+ return;
191
+ }
192
+ }
193
+ }
194
+
195
+ [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath
196
+ error:&error];
197
+ if (error) {
198
+ failCallback(error);
199
+ return;
200
+ }
201
+ }
202
+
203
+ [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath
204
+ destFolder:newUpdateFolderPath
205
+ error:&error];
206
+ if (error) {
207
+ failCallback(error);
208
+ return;
209
+ }
210
+
211
+ [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath
212
+ error:&nonFailingError];
213
+ if (nonFailingError) {
214
+ CPLog(@"Error deleting downloaded file: %@", nonFailingError);
215
+ nonFailingError = nil;
216
+ }
217
+
218
+ NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath
219
+ expectedFileName:expectedBundleFileName
220
+ error:&error];
221
+
222
+ if (error) {
223
+ failCallback(error);
224
+ return;
225
+ }
226
+
227
+ if (relativeBundlePath) {
228
+ [mutableUpdatePackage setValue:relativeBundlePath forKey:RelativeBundlePathKey];
229
+ } else {
230
+ NSString *errorMessage = [NSString stringWithFormat:@"Update is invalid - A JS bundle file named \"%@\" could not be found within the downloaded contents. Please ensure that your app is syncing with the correct deployment and that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.", expectedBundleFileName];
231
+
232
+ error = [CodePushErrorUtils errorWithMessage:errorMessage];
233
+
234
+ failCallback(error);
235
+ return;
236
+ }
237
+
238
+ if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) {
239
+ [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath
240
+ error:&error];
241
+ if (error) {
242
+ failCallback(error);
243
+ return;
244
+ }
245
+ }
246
+
247
+ CPLog((isDiffUpdate) ? @"Applying diff update." : @"Applying full update.");
248
+
249
+ BOOL isSignatureVerificationEnabled = (publicKey != nil);
250
+
251
+ NSString *signatureFilePath = [CodePushUpdateUtils getSignatureFilePath:newUpdateFolderPath];
252
+ BOOL isSignatureAppearedInBundle = [[NSFileManager defaultManager] fileExistsAtPath:signatureFilePath];
253
+
254
+ if (isSignatureVerificationEnabled) {
255
+ if (isSignatureAppearedInBundle) {
256
+ if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
257
+ expectedHash:newUpdateHash
258
+ error:&error]) {
259
+ CPLog(@"The update contents failed the data integrity check.");
260
+ if (!error) {
261
+ error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."];
262
+ }
263
+
264
+ failCallback(error);
265
+ return;
266
+ } else {
267
+ CPLog(@"The update contents succeeded the data integrity check.");
268
+ }
269
+ BOOL isSignatureValid = [CodePushUpdateUtils verifyUpdateSignatureFor:newUpdateFolderPath
270
+ expectedHash:newUpdateHash
271
+ withPublicKey:publicKey
272
+ error:&error];
273
+ if (!isSignatureValid) {
274
+ CPLog(@"The update contents failed code signing check.");
275
+ if (!error) {
276
+ error = [CodePushErrorUtils errorWithMessage:@"The update contents failed code signing check."];
277
+ }
278
+ failCallback(error);
279
+ return;
280
+ } else {
281
+ CPLog(@"The update contents succeeded the code signing check.");
282
+ }
283
+ } else {
284
+ error = [CodePushErrorUtils errorWithMessage:
285
+ @"Error! Public key was provided but there is no JWT signature within app bundle to verify " \
286
+ "Possible reasons, why that might happen: \n" \
287
+ "1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\n" \
288
+ "2. You've been released CodePush bundle update without providing --privateKeyPath option."];
289
+ failCallback(error);
290
+ return;
291
+ }
292
+
293
+ } else {
294
+ BOOL needToVerifyHash;
295
+ if (isSignatureAppearedInBundle) {
296
+ CPLog(@"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed" \
297
+ " because there is no public key configured. " \
298
+ "Please ensure that public key is properly configured within your application.");
299
+ needToVerifyHash = true;
300
+ } else {
301
+ needToVerifyHash = (isDiffUpdate || cameFromDiffHandler);
302
+ }
303
+ if(needToVerifyHash){
304
+ if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
305
+ expectedHash:newUpdateHash
306
+ error:&error]) {
307
+ CPLog(@"The update contents failed the data integrity check.");
308
+ if (!error) {
309
+ error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."];
310
+ }
311
+
312
+ failCallback(error);
313
+ return;
314
+ } else {
315
+ CPLog(@"The update contents succeeded the data integrity check.");
316
+ }
317
+ }
318
+ }
319
+ } else {
320
+ [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath
321
+ withIntermediateDirectories:YES
322
+ attributes:nil
323
+ error:&error];
324
+ [[NSFileManager defaultManager] moveItemAtPath:downloadFilePath
325
+ toPath:bundleFilePath
326
+ error:&error];
327
+ if (error) {
328
+ failCallback(error);
329
+ return;
330
+ }
331
+ }
332
+
333
+ NSData *updateSerializedData = [NSJSONSerialization dataWithJSONObject:mutableUpdatePackage
334
+ options:0
335
+ error:&error];
336
+ NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData
337
+ encoding:NSUTF8StringEncoding];
338
+
339
+ [packageJsonString writeToFile:newUpdateMetadataPath
340
+ atomically:YES
341
+ encoding:NSUTF8StringEncoding
342
+ error:&error];
343
+ if (error) {
344
+ failCallback(error);
345
+ } else {
346
+ doneCallback();
347
+ }
348
+ };
349
+
350
+ __block BOOL fallbackStarted = NO;
351
+
352
+ void (^startFullDownload)(void) = ^{
353
+ if (fallbackStarted) return;
354
+ fallbackStarted = YES;
355
+
356
+ NSError *cleanupErr = nil;
357
+ [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath error:&cleanupErr];
358
+ [[NSFileManager defaultManager] removeItemAtPath:[CodePushPackage getUnzippedFolderPath] error:nil];
359
+
360
+ CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc]
361
+ init:downloadFilePath
362
+ operationQueue:operationQueue
363
+ progressCallback:progressCallback
364
+ doneCallback:commonDone
365
+ failCallback:failCallback];
366
+
367
+ CPLog(@"Fallback to FULL download handler");
368
+ [downloadHandler download:singleUrl];
369
+ };
370
+
371
+ void (^diffFailThenFallback)(NSError *err) = ^(NSError *err) {
372
+ if (singleUrl.length == 0) {
373
+ failCallback(err);
374
+ return;
375
+ }
376
+ startFullDownload();
377
+ };
378
+
379
+
380
+ if (cameFromDiffHandler) {
381
+ NSString *assetsUrl = updatePackage[@"assetDownloadUrl"] ?: updatePackage[@"asset_download_url"];
382
+ NSString *assetHash = updatePackage[@"assetHash"] ?: updatePackage[@"asset_hash"];
383
+
384
+ NSError *pkgErr = nil;
385
+ NSDictionary *currentPackage = [CodePushPackage getCurrentPackage:&pkgErr];
386
+
387
+ NSError *assetsError = nil;
388
+ NSString *nativeAssetHash = [CodePushUpdateUtils getHashForBinaryAssets:&assetsError];
389
+
390
+ CodePushDiffDownloadHandler *diffHandler = [[CodePushDiffDownloadHandler alloc]
391
+ init:downloadFilePath
392
+ operationQueue:operationQueue
393
+ progressCallback:progressCallback
394
+ doneCallback:commonDone
395
+ failCallback:diffFailThenFallback];
396
+
397
+ CPLog(@"Diff download handler");
398
+
399
+ [diffHandler downloadWithDiffUrl:bundleDiffUrl assetsUrl:assetsUrl assetHash:assetHash nativeAssetHash:nativeAssetHash currentPackage:currentPackage];
400
+ } else {
401
+ NSString *singleUrl = updatePackage[@"downloadUrl"] ?: updatePackage[@"download_url"];
402
+
403
+ CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc]
404
+ init:downloadFilePath
405
+ operationQueue:operationQueue
406
+ progressCallback:progressCallback
407
+ doneCallback:commonDone
408
+ failCallback:failCallback];
409
+
410
+ CPLog(@"Full download handler");
411
+
412
+ [downloadHandler download:singleUrl];
413
+ }
345
414
  }
346
415
 
347
416
  + (NSString *)getCodePushPath
@@ -350,7 +419,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
350
419
  if ([CodePush isUsingTestConfiguration]) {
351
420
  codePushPath = [codePushPath stringByAppendingPathComponent:@"TestPackages"];
352
421
  }
353
-
422
+
354
423
  return codePushPath;
355
424
  }
356
425
 
@@ -367,17 +436,17 @@ static NSString *const UnzippedFolderName = @"unzipped";
367
436
  + (NSString *)getCurrentPackageBundlePath:(NSError **)error
368
437
  {
369
438
  NSString *packageFolder = [self getCurrentPackageFolderPath:error];
370
-
439
+
371
440
  if (!packageFolder) {
372
441
  return nil;
373
442
  }
374
-
443
+
375
444
  NSDictionary *currentPackage = [self getCurrentPackage:error];
376
-
445
+
377
446
  if (!currentPackage) {
378
447
  return nil;
379
448
  }
380
-
449
+
381
450
  NSString *relativeBundlePath = [currentPackage objectForKey:RelativeBundlePathKey];
382
451
  if (relativeBundlePath) {
383
452
  return [packageFolder stringByAppendingPathComponent:relativeBundlePath];
@@ -392,24 +461,24 @@ static NSString *const UnzippedFolderName = @"unzipped";
392
461
  if (!info) {
393
462
  return nil;
394
463
  }
395
-
464
+
396
465
  return info[@"currentPackage"];
397
466
  }
398
467
 
399
468
  + (NSString *)getCurrentPackageFolderPath:(NSError **)error
400
469
  {
401
470
  NSDictionary *info = [self getCurrentPackageInfo:error];
402
-
471
+
403
472
  if (!info) {
404
473
  return nil;
405
474
  }
406
-
475
+
407
476
  NSString *packageHash = info[@"currentPackage"];
408
-
477
+
409
478
  if (!packageHash) {
410
479
  return nil;
411
480
  }
412
-
481
+
413
482
  return [self getPackageFolderPath:packageHash];
414
483
  }
415
484
 
@@ -419,14 +488,14 @@ static NSString *const UnzippedFolderName = @"unzipped";
419
488
  if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) {
420
489
  return [NSMutableDictionary dictionary];
421
490
  }
422
-
491
+
423
492
  NSString *content = [NSString stringWithContentsOfFile:statusFilePath
424
493
  encoding:NSUTF8StringEncoding
425
494
  error:error];
426
495
  if (!content) {
427
496
  return nil;
428
497
  }
429
-
498
+
430
499
  NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
431
500
  NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data
432
501
  options:kNilOptions
@@ -434,7 +503,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
434
503
  if (!json) {
435
504
  return nil;
436
505
  }
437
-
506
+
438
507
  return [json mutableCopy];
439
508
  }
440
509
 
@@ -448,18 +517,18 @@ static NSString *const UnzippedFolderName = @"unzipped";
448
517
  {
449
518
  NSString *updateDirectoryPath = [self getPackageFolderPath:packageHash];
450
519
  NSString *updateMetadataFilePath = [updateDirectoryPath stringByAppendingPathComponent:UpdateMetadataFileName];
451
-
520
+
452
521
  if (![[NSFileManager defaultManager] fileExistsAtPath:updateMetadataFilePath]) {
453
522
  return nil;
454
523
  }
455
-
524
+
456
525
  NSString *updateMetadataString = [NSString stringWithContentsOfFile:updateMetadataFilePath
457
526
  encoding:NSUTF8StringEncoding
458
527
  error:error];
459
528
  if (!updateMetadataString) {
460
529
  return nil;
461
530
  }
462
-
531
+
463
532
  NSData *updateMetadata = [updateMetadataString dataUsingEncoding:NSUTF8StringEncoding];
464
533
  return [NSJSONSerialization JSONObjectWithData:updateMetadata
465
534
  options:kNilOptions
@@ -477,7 +546,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
477
546
  if (!packageHash) {
478
547
  return nil;
479
548
  }
480
-
549
+
481
550
  return [CodePushPackage getPackage:packageHash error:error];
482
551
  }
483
552
 
@@ -487,7 +556,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
487
556
  if (!info) {
488
557
  return nil;
489
558
  }
490
-
559
+
491
560
  return info[@"previousPackage"];
492
561
  }
493
562
 
@@ -507,11 +576,11 @@ static NSString *const UnzippedFolderName = @"unzipped";
507
576
  {
508
577
  NSString *packageHash = updatePackage[@"packageHash"];
509
578
  NSMutableDictionary *info = [self getCurrentPackageInfo:error];
510
-
579
+
511
580
  if (!info) {
512
581
  return NO;
513
582
  }
514
-
583
+
515
584
  if (packageHash && [packageHash isEqualToString:info[@"currentPackage"]]) {
516
585
  // The current package is already the one being installed, so we should no-op.
517
586
  return YES;
@@ -542,7 +611,7 @@ static NSString *const UnzippedFolderName = @"unzipped";
542
611
  }
543
612
  [info setValue:info[@"currentPackage"] forKey:@"previousPackage"];
544
613
  }
545
-
614
+
546
615
  [info setValue:packageHash forKey:@"currentPackage"];
547
616
  return [self updateCurrentPackageInfo:info
548
617
  error:error];
@@ -556,23 +625,23 @@ static NSString *const UnzippedFolderName = @"unzipped";
556
625
  CPLog(@"Error getting current package info: %@", error);
557
626
  return;
558
627
  }
559
-
560
- NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];
628
+
629
+ NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];
561
630
  if (!currentPackageFolderPath) {
562
631
  CPLog(@"Error getting current package folder path: %@", error);
563
632
  return;
564
633
  }
565
-
634
+
566
635
  NSError *deleteError;
567
636
  BOOL result = [[NSFileManager defaultManager] removeItemAtPath:currentPackageFolderPath
568
637
  error:&deleteError];
569
638
  if (!result) {
570
639
  CPLog(@"Error deleting current package contents at %@ error %@", currentPackageFolderPath, deleteError);
571
640
  }
572
-
641
+
573
642
  [info setValue:info[@"previousPackage"] forKey:@"currentPackage"];
574
643
  [info removeObjectForKey:@"previousPackage"];
575
-
644
+
576
645
  [self updateCurrentPackageInfo:info error:&error];
577
646
  }
578
647