From 7ad0fdcc7c1ad3b71093ce0da47e98fd3006333d Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 15:54:27 -0800 Subject: [PATCH 1/7] verify hash after download ios --- CodePush.xcodeproj/project.pbxproj | 21 ++- .../CodePushDemoApp.xcodeproj/project.pbxproj | 8 +- CodePush.h => iOS/CodePush.h | 18 ++ CodePush.m => iOS/CodePush.m | 0 CodePushConfig.m => iOS/CodePushConfig.m | 0 .../CodePushDownloadHandler.m | 0 CodePushPackage.m => iOS/CodePushPackage.m | 149 ++++++----------- .../CodePushTelemetryManager.m | 0 iOS/CodePushUtils.m | 156 ++++++++++++++++++ .../RCTConvert+CodePushInstallMode.m | 0 {SSZipArchive => iOS/SSZipArchive}/Common.h | 0 {SSZipArchive => iOS/SSZipArchive}/README.md | 0 .../SSZipArchive}/SSZipArchive.h | 0 .../SSZipArchive}/SSZipArchive.m | 0 {SSZipArchive => iOS/SSZipArchive}/aes/aes.h | 0 .../SSZipArchive}/aes/aes_via_ace.h | 0 .../SSZipArchive}/aes/aescrypt.c | 0 .../SSZipArchive}/aes/aeskey.c | 0 .../SSZipArchive}/aes/aesopt.h | 0 .../SSZipArchive}/aes/aestab.c | 0 .../SSZipArchive}/aes/aestab.h | 0 .../SSZipArchive}/aes/brg_endian.h | 0 .../SSZipArchive}/aes/brg_types.h | 0 .../SSZipArchive}/aes/entropy.c | 0 .../SSZipArchive}/aes/entropy.h | 0 .../SSZipArchive}/aes/fileenc.c | 0 .../SSZipArchive}/aes/fileenc.h | 0 {SSZipArchive => iOS/SSZipArchive}/aes/hmac.c | 0 {SSZipArchive => iOS/SSZipArchive}/aes/hmac.h | 0 {SSZipArchive => iOS/SSZipArchive}/aes/prng.c | 0 {SSZipArchive => iOS/SSZipArchive}/aes/prng.h | 0 .../SSZipArchive}/aes/pwd2key.c | 0 .../SSZipArchive}/aes/pwd2key.h | 0 {SSZipArchive => iOS/SSZipArchive}/aes/sha1.c | 0 {SSZipArchive => iOS/SSZipArchive}/aes/sha1.h | 0 .../SSZipArchive}/minizip/crypt.h | 0 .../SSZipArchive}/minizip/ioapi.c | 0 .../SSZipArchive}/minizip/ioapi.h | 0 .../SSZipArchive}/minizip/mztools.c | 0 .../SSZipArchive}/minizip/mztools.h | 0 .../SSZipArchive}/minizip/unzip.c | 0 .../SSZipArchive}/minizip/unzip.h | 0 .../SSZipArchive}/minizip/zip.c | 0 .../SSZipArchive}/minizip/zip.h | 0 44 files changed, 244 insertions(+), 108 deletions(-) rename CodePush.h => iOS/CodePush.h (82%) rename CodePush.m => iOS/CodePush.m (100%) rename CodePushConfig.m => iOS/CodePushConfig.m (100%) rename CodePushDownloadHandler.m => iOS/CodePushDownloadHandler.m (100%) rename CodePushPackage.m => iOS/CodePushPackage.m (83%) rename CodePushTelemetryManager.m => iOS/CodePushTelemetryManager.m (100%) create mode 100644 iOS/CodePushUtils.m rename RCTConvert+CodePushInstallMode.m => iOS/RCTConvert+CodePushInstallMode.m (100%) rename {SSZipArchive => iOS/SSZipArchive}/Common.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/README.md (100%) rename {SSZipArchive => iOS/SSZipArchive}/SSZipArchive.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/SSZipArchive.m (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aes.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aes_via_ace.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aescrypt.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aeskey.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aesopt.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aestab.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/aestab.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/brg_endian.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/brg_types.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/entropy.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/entropy.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/fileenc.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/fileenc.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/hmac.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/hmac.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/prng.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/prng.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/pwd2key.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/pwd2key.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/sha1.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/aes/sha1.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/crypt.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/ioapi.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/ioapi.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/mztools.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/mztools.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/unzip.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/unzip.h (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/zip.c (100%) rename {SSZipArchive => iOS/SSZipArchive}/minizip/zip.h (100%) diff --git a/CodePush.xcodeproj/project.pbxproj b/CodePush.xcodeproj/project.pbxproj index d3c086c..fcf5bcf 100644 --- a/CodePush.xcodeproj/project.pbxproj +++ b/CodePush.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 13BE3DEE1AC21097009241FE /* CodePush.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.m */; }; 1B23B9141BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */; }; + 540D20121C7684FE00D6EF41 /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 540D20111C7684FE00D6EF41 /* CodePushUtils.m */; }; 5421FE311C58AD5A00986A55 /* CodePushTelemetryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */; }; 54A0026C1C0E2880004C3CEC /* aescrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A0024C1C0E2880004C3CEC /* aescrypt.c */; }; 54A0026D1C0E2880004C3CEC /* aeskey.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A0024D1C0E2880004C3CEC /* aeskey.c */; }; @@ -43,10 +44,11 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCodePush.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodePush.h; sourceTree = ""; }; - 13BE3DED1AC21097009241FE /* CodePush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodePush.m; sourceTree = ""; }; - 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+CodePushInstallMode.m"; sourceTree = ""; }; - 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodePushTelemetryManager.m; sourceTree = ""; }; + 13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodePush.h; path = iOS/CodePush.h; sourceTree = ""; }; + 13BE3DED1AC21097009241FE /* CodePush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePush.m; path = iOS/CodePush.m; sourceTree = ""; }; + 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+CodePushInstallMode.m"; path = "iOS/RCTConvert+CodePushInstallMode.m"; sourceTree = ""; }; + 540D20111C7684FE00D6EF41 /* CodePushUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushUtils.m; path = iOS/CodePushUtils.m; sourceTree = ""; }; + 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushTelemetryManager.m; path = iOS/CodePushTelemetryManager.m; sourceTree = ""; }; 54A0024A1C0E2880004C3CEC /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; 54A0024B1C0E2880004C3CEC /* aes_via_ace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes_via_ace.h; sourceTree = ""; }; 54A0024C1C0E2880004C3CEC /* aescrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aescrypt.c; sourceTree = ""; }; @@ -80,9 +82,9 @@ 54A002691C0E2880004C3CEC /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; 54A0026A1C0E2880004C3CEC /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchive.h; sourceTree = ""; }; 54A0026B1C0E2880004C3CEC /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchive.m; sourceTree = ""; }; - 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodePushDownloadHandler.m; sourceTree = ""; }; - 810D4E6C1B96935000B397E9 /* CodePushPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodePushPackage.m; sourceTree = ""; }; - 81D51F391B6181C2000DA084 /* CodePushConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CodePushConfig.m; sourceTree = ""; }; + 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushDownloadHandler.m; path = iOS/CodePushDownloadHandler.m; sourceTree = ""; }; + 810D4E6C1B96935000B397E9 /* CodePushPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushPackage.m; path = iOS/CodePushPackage.m; sourceTree = ""; }; + 81D51F391B6181C2000DA084 /* CodePushConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushConfig.m; path = iOS/CodePushConfig.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,7 +115,8 @@ 54A0026A1C0E2880004C3CEC /* SSZipArchive.h */, 54A0026B1C0E2880004C3CEC /* SSZipArchive.m */, ); - path = SSZipArchive; + name = SSZipArchive; + path = iOS/SSZipArchive; sourceTree = ""; }; 54A002491C0E2880004C3CEC /* aes */ = { @@ -169,6 +172,7 @@ 810D4E6C1B96935000B397E9 /* CodePushPackage.m */, 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */, 81D51F391B6181C2000DA084 /* CodePushConfig.m */, + 540D20111C7684FE00D6EF41 /* CodePushUtils.m */, 13BE3DEC1AC21097009241FE /* CodePush.h */, 13BE3DED1AC21097009241FE /* CodePush.m */, 134814211AA4EA7D00B7C361 /* Products */, @@ -232,6 +236,7 @@ buildActionMask = 2147483647; files = ( 54A0026D1C0E2880004C3CEC /* aeskey.c in Sources */, + 540D20121C7684FE00D6EF41 /* CodePushUtils.m in Sources */, 54A0026E1C0E2880004C3CEC /* aestab.c in Sources */, 54A002761C0E2880004C3CEC /* mztools.c in Sources */, 54A002781C0E2880004C3CEC /* zip.c in Sources */, diff --git a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj index 3eac84e..2e8d08a 100644 --- a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj +++ b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj @@ -684,7 +684,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../..", + "$(SRCROOT)/../../../iOS/**", "$(SRCROOT)/../node_modules/react-native/Libraries/Text/", ); INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist; @@ -708,7 +708,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../..", + "$(SRCROOT)/../../../iOS/**", "$(SRCROOT)/../node_modules/react-native/Libraries/Text/", ); INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist; @@ -727,7 +727,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../..", + "$(SRCROOT)/../../../iOS/**", ); INFOPLIST_FILE = "$(SRCROOT)/CodePushDemoApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -747,7 +747,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../..", + "$(SRCROOT)/../../../iOS/**", ); INFOPLIST_FILE = "$(SRCROOT)/CodePushDemoApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/CodePush.h b/iOS/CodePush.h similarity index 82% rename from CodePush.h rename to iOS/CodePush.h index 57e0770..4920700 100644 --- a/CodePush.h +++ b/iOS/CodePush.h @@ -104,6 +104,24 @@ failCallback:(void (^)(NSError *err))failCallback; @end +@interface CodePushUtils : NSObject + ++ (void)addContentsOfFolderToManifest:(NSString *)folderPath + pathPrefix:(NSString *)pathPrefix + manifest:(NSMutableArray *)manifest + error:(NSError **)error; ++ (NSString *)computeHash:(NSData *)inputData; ++ (void)copyEntriesInFolder:(NSString *)sourceFolder + destFolder:(NSString *)destFolder + error:(NSError **)error; ++ (NSString *)findMainBundleInFolder:(NSString *)folderPath + error:(NSError **)error; ++ (BOOL)verifyHashForZipUpdate:(NSString *)finalUpdateFolder + expectedHash:(NSString *)expectedHash + error:(NSError **)error; + +@end + typedef NS_ENUM(NSInteger, CodePushInstallMode) { CodePushInstallModeImmediate, CodePushInstallModeOnNextRestart, diff --git a/CodePush.m b/iOS/CodePush.m similarity index 100% rename from CodePush.m rename to iOS/CodePush.m diff --git a/CodePushConfig.m b/iOS/CodePushConfig.m similarity index 100% rename from CodePushConfig.m rename to iOS/CodePushConfig.m diff --git a/CodePushDownloadHandler.m b/iOS/CodePushDownloadHandler.m similarity index 100% rename from CodePushDownloadHandler.m rename to iOS/CodePushDownloadHandler.m diff --git a/CodePushPackage.m b/iOS/CodePushPackage.m similarity index 83% rename from CodePushPackage.m rename to iOS/CodePushPackage.m index 764e8e3..52d16f9 100644 --- a/CodePushPackage.m +++ b/iOS/CodePushPackage.m @@ -1,5 +1,6 @@ #import "CodePush.h" #import "SSZipArchive.h" +#include @implementation CodePushPackage @@ -154,7 +155,7 @@ NSString * const UnzippedFolderName = @"unzipped"; NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:error]; - + return jsonDict; } } @@ -203,7 +204,9 @@ NSString * const UnzippedFolderName = @"unzipped"; doneCallback:(void (^)())doneCallback failCallback:(void (^)(NSError *err))failCallback { - NSString *newPackageFolderPath = [self getPackageFolderPath:updatePackage[@"packageHash"]]; + NSString *newPackageHash = updatePackage[@"packageHash"]; + NSString *newPackageFolderPath = [self getPackageFolderPath:newPackageHash]; + NSString *newPackageMetadataPath = [newPackageFolderPath stringByAppendingPathComponent:@"app.json"]; NSError *error; if ([[NSFileManager defaultManager] fileExistsAtPath:newPackageFolderPath]) { @@ -288,18 +291,26 @@ NSString * const UnzippedFolderName = @"unzipped"; NSArray *deletedFiles = manifestJSON[@"deletedFiles"]; for (NSString *deletedFileName in deletedFiles) { [[NSFileManager defaultManager] removeItemAtPath:[newPackageFolderPath stringByAppendingPathComponent:deletedFileName] - error:&nonFailingError]; - - if (nonFailingError) { - NSLog(@"Error deleting file from current package: %@", nonFailingError); - nonFailingError = nil; + error:&error]; + if (error) { + failCallback(error); + return; } } } - [CodePushPackage copyEntriesInFolder:unzippedFolderPath - destFolder:newPackageFolderPath - error:&error]; + if ([[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]) { + [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + [CodePushUtils copyEntriesInFolder:unzippedFolderPath + destFolder:newPackageFolderPath + error:&error]; if (error) { failCallback(error); return; @@ -312,8 +323,8 @@ NSString * const UnzippedFolderName = @"unzipped"; nonFailingError = nil; } - NSString *relativeBundlePath = [self findMainBundleInFolder:newPackageFolderPath - error:&error]; + NSString *relativeBundlePath = [CodePushUtils findMainBundleInFolder:newPackageFolderPath + error:&error]; if (error) { failCallback(error); return; @@ -347,6 +358,33 @@ NSString * const UnzippedFolderName = @"unzipped"; failCallback(error); return; } + + if ([[NSFileManager defaultManager] fileExistsAtPath:newPackageMetadataPath]) { + [[NSFileManager defaultManager] removeItemAtPath:newPackageMetadataPath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + if (![CodePushUtils verifyHashForZipUpdate:newPackageFolderPath + expectedHash:newPackageHash + error:&error]) { + if (error) { + failCallback(error); + return; + } + + error = [[NSError alloc] initWithDomain:CodePushErrorDomain + code:CodePushErrorCode + userInfo:@{ + NSLocalizedDescriptionKey: + NSLocalizedString(@"The update contents failed the data integrity check.", nil) + }]; + failCallback(error); + return; + } } else { [[NSFileManager defaultManager] createDirectoryAtPath:newPackageFolderPath withIntermediateDirectories:YES @@ -367,7 +405,7 @@ NSString * const UnzippedFolderName = @"unzipped"; NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData encoding:NSUTF8StringEncoding]; - [packageJsonString writeToFile:[newPackageFolderPath stringByAppendingPathComponent:@"app.json"] + [packageJsonString writeToFile:newPackageMetadataPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; @@ -377,93 +415,12 @@ NSString * const UnzippedFolderName = @"unzipped"; doneCallback(); } } - + failCallback:failCallback]; [downloadHandler download:updatePackage[@"downloadUrl"]]; } -+ (NSString *)findMainBundleInFolder:(NSString *)folderPath - error:(NSError **)error -{ - NSArray* folderFiles = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:folderPath - error:error]; - if (*error) { - return nil; - } - - for (NSString *fileName in folderFiles) { - NSString *fullFilePath = [folderPath stringByAppendingPathComponent:fileName]; - BOOL isDir = NO; - if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath - isDirectory:&isDir] && isDir) { - NSString *mainBundlePathInFolder = [self findMainBundleInFolder:fullFilePath error:error]; - if (*error) { - return nil; - } - - if (mainBundlePathInFolder) { - return [fileName stringByAppendingPathComponent:mainBundlePathInFolder]; - } - } else if ([[fileName pathExtension] isEqualToString:@"bundle"] || - [[fileName pathExtension] isEqualToString:@"jsbundle"] || - [[fileName pathExtension] isEqualToString:@"js"]) { - return fileName; - } - } - - return nil; -} - - -+ (void)copyEntriesInFolder:(NSString *)sourceFolder - destFolder:(NSString *)destFolder - error:(NSError **)error - -{ - NSArray* files = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:sourceFolder - error:error]; - if (*error) { - return; - } - - for (NSString *fileName in files) { - NSString * fullFilePath = [sourceFolder stringByAppendingPathComponent:fileName]; - BOOL isDir = NO; - if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath - isDirectory:&isDir] && isDir) { - NSString *nestedDestFolder = [destFolder stringByAppendingPathComponent:fileName]; - [self copyEntriesInFolder:fullFilePath - destFolder:nestedDestFolder - error:error]; - } else { - NSString *destFileName = [destFolder stringByAppendingPathComponent:fileName]; - if ([[NSFileManager defaultManager] fileExistsAtPath:destFileName]) { - [[NSFileManager defaultManager] removeItemAtPath:destFileName error:error]; - if (*error) { - return; - } - } - if (![[NSFileManager defaultManager] fileExistsAtPath:destFolder]) { - [[NSFileManager defaultManager] createDirectoryAtPath:destFolder - withIntermediateDirectories:YES - attributes:nil - error:error]; - if (*error) { - return; - } - } - - [[NSFileManager defaultManager] copyItemAtPath:fullFilePath toPath:destFileName error:error]; - if (*error) { - return; - } - } - } -} - + (void)installPackage:(NSDictionary *)updatePackage removePendingUpdate:(BOOL)removePendingUpdate error:(NSError **)error @@ -502,7 +459,7 @@ NSString * const UnzippedFolderName = @"unzipped"; } [info setValue:packageHash forKey:@"currentPackage"]; - + [self updateCurrentPackageInfo:info error:error]; } diff --git a/CodePushTelemetryManager.m b/iOS/CodePushTelemetryManager.m similarity index 100% rename from CodePushTelemetryManager.m rename to iOS/CodePushTelemetryManager.m diff --git a/iOS/CodePushUtils.m b/iOS/CodePushUtils.m new file mode 100644 index 0000000..c187862 --- /dev/null +++ b/iOS/CodePushUtils.m @@ -0,0 +1,156 @@ +#import "CodePush.h" +#include + +@implementation CodePushUtils + ++ (void)addContentsOfFolderToManifest:(NSString *)folderPath + pathPrefix:(NSString *)pathPrefix + manifest:(NSMutableArray *)manifest + error:(NSError **)error +{ + NSArray* folderFiles = [[NSFileManager defaultManager] + contentsOfDirectoryAtPath:folderPath + error:error]; + if (*error) { + return; + } + + for (NSString *fileName in folderFiles) { + NSString *fullFilePath = [folderPath stringByAppendingPathComponent:fileName]; + NSString *relativePath = [pathPrefix stringByAppendingPathComponent:fileName]; + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath + isDirectory:&isDir] && isDir) { + [self addContentsOfFolderToManifest:fullFilePath + pathPrefix:relativePath + manifest:manifest + error:error]; + if (*error) { + return; + } + } else { + NSData *fileContents = [NSData dataWithContentsOfFile:fullFilePath]; + NSString *fileContentsHash = [self computeHash:fileContents]; + [manifest addObject:[[relativePath stringByAppendingString:@":"] stringByAppendingString:fileContentsHash]]; + } + } +} + ++ (NSString *)computeHash:(NSData *)inputData +{ + uint8_t digest[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(inputData.bytes, inputData.length, digest); + NSMutableString* inputHash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { + [inputHash appendFormat:@"%02x", digest[i]]; + } + + return inputHash; +} + ++ (void)copyEntriesInFolder:(NSString *)sourceFolder + destFolder:(NSString *)destFolder + error:(NSError **)error +{ + NSArray* files = [[NSFileManager defaultManager] + contentsOfDirectoryAtPath:sourceFolder + error:error]; + if (*error) { + return; + } + + for (NSString *fileName in files) { + NSString * fullFilePath = [sourceFolder stringByAppendingPathComponent:fileName]; + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath + isDirectory:&isDir] && isDir) { + NSString *nestedDestFolder = [destFolder stringByAppendingPathComponent:fileName]; + [self copyEntriesInFolder:fullFilePath + destFolder:nestedDestFolder + error:error]; + } else { + NSString *destFileName = [destFolder stringByAppendingPathComponent:fileName]; + if ([[NSFileManager defaultManager] fileExistsAtPath:destFileName]) { + [[NSFileManager defaultManager] removeItemAtPath:destFileName error:error]; + if (*error) { + return; + } + } + if (![[NSFileManager defaultManager] fileExistsAtPath:destFolder]) { + [[NSFileManager defaultManager] createDirectoryAtPath:destFolder + withIntermediateDirectories:YES + attributes:nil + error:error]; + if (*error) { + return; + } + } + + [[NSFileManager defaultManager] copyItemAtPath:fullFilePath toPath:destFileName error:error]; + if (*error) { + return; + } + } + } +} + ++ (NSString *)findMainBundleInFolder:(NSString *)folderPath + error:(NSError **)error +{ + NSArray* folderFiles = [[NSFileManager defaultManager] + contentsOfDirectoryAtPath:folderPath + error:error]; + if (*error) { + return nil; + } + + for (NSString *fileName in folderFiles) { + NSString *fullFilePath = [folderPath stringByAppendingPathComponent:fileName]; + BOOL isDir = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath + isDirectory:&isDir] && isDir) { + NSString *mainBundlePathInFolder = [self findMainBundleInFolder:fullFilePath error:error]; + if (*error) { + return nil; + } + + if (mainBundlePathInFolder) { + return [fileName stringByAppendingPathComponent:mainBundlePathInFolder]; + } + } else if ([[fileName pathExtension] isEqualToString:@"bundle"] || + [[fileName pathExtension] isEqualToString:@"jsbundle"] || + [[fileName pathExtension] isEqualToString:@"js"]) { + return fileName; + } + } + + return nil; +} + ++ (BOOL)verifyHashForZipUpdate:(NSString *)finalUpdateFolder + expectedHash:(NSString *)expectedHash + error:(NSError **)error +{ + NSMutableArray *updateContentsManifest = [NSMutableArray array]; + [self addContentsOfFolderToManifest:finalUpdateFolder + pathPrefix:@"" + manifest:updateContentsManifest + error:error]; + if (*error) { + return NO; + } + + NSArray *sortedUpdateContentsManifest = [updateContentsManifest sortedArrayUsingSelector:@selector(compare:)]; + NSData *updateContentsManifestData = [NSJSONSerialization dataWithJSONObject:sortedUpdateContentsManifest + options:kNilOptions + error:error]; + NSString *updateContentsManifestString = [[NSString alloc] initWithData:updateContentsManifestData + encoding:NSUTF8StringEncoding]; + // The JSON serialization turns path seperators into "\/", e.g. "CodePush\/assets\/image.png" + updateContentsManifestString = [updateContentsManifestString stringByReplacingOccurrencesOfString:@"\\/" + withString:@"/"]; + NSString *updateContentsManifestHash = [self computeHash:[NSData dataWithBytes:updateContentsManifestString.UTF8String length:updateContentsManifestString.length]]; + return [updateContentsManifestHash isEqualToString:expectedHash]; +} + +@end \ No newline at end of file diff --git a/RCTConvert+CodePushInstallMode.m b/iOS/RCTConvert+CodePushInstallMode.m similarity index 100% rename from RCTConvert+CodePushInstallMode.m rename to iOS/RCTConvert+CodePushInstallMode.m diff --git a/SSZipArchive/Common.h b/iOS/SSZipArchive/Common.h similarity index 100% rename from SSZipArchive/Common.h rename to iOS/SSZipArchive/Common.h diff --git a/SSZipArchive/README.md b/iOS/SSZipArchive/README.md similarity index 100% rename from SSZipArchive/README.md rename to iOS/SSZipArchive/README.md diff --git a/SSZipArchive/SSZipArchive.h b/iOS/SSZipArchive/SSZipArchive.h similarity index 100% rename from SSZipArchive/SSZipArchive.h rename to iOS/SSZipArchive/SSZipArchive.h diff --git a/SSZipArchive/SSZipArchive.m b/iOS/SSZipArchive/SSZipArchive.m similarity index 100% rename from SSZipArchive/SSZipArchive.m rename to iOS/SSZipArchive/SSZipArchive.m diff --git a/SSZipArchive/aes/aes.h b/iOS/SSZipArchive/aes/aes.h similarity index 100% rename from SSZipArchive/aes/aes.h rename to iOS/SSZipArchive/aes/aes.h diff --git a/SSZipArchive/aes/aes_via_ace.h b/iOS/SSZipArchive/aes/aes_via_ace.h similarity index 100% rename from SSZipArchive/aes/aes_via_ace.h rename to iOS/SSZipArchive/aes/aes_via_ace.h diff --git a/SSZipArchive/aes/aescrypt.c b/iOS/SSZipArchive/aes/aescrypt.c similarity index 100% rename from SSZipArchive/aes/aescrypt.c rename to iOS/SSZipArchive/aes/aescrypt.c diff --git a/SSZipArchive/aes/aeskey.c b/iOS/SSZipArchive/aes/aeskey.c similarity index 100% rename from SSZipArchive/aes/aeskey.c rename to iOS/SSZipArchive/aes/aeskey.c diff --git a/SSZipArchive/aes/aesopt.h b/iOS/SSZipArchive/aes/aesopt.h similarity index 100% rename from SSZipArchive/aes/aesopt.h rename to iOS/SSZipArchive/aes/aesopt.h diff --git a/SSZipArchive/aes/aestab.c b/iOS/SSZipArchive/aes/aestab.c similarity index 100% rename from SSZipArchive/aes/aestab.c rename to iOS/SSZipArchive/aes/aestab.c diff --git a/SSZipArchive/aes/aestab.h b/iOS/SSZipArchive/aes/aestab.h similarity index 100% rename from SSZipArchive/aes/aestab.h rename to iOS/SSZipArchive/aes/aestab.h diff --git a/SSZipArchive/aes/brg_endian.h b/iOS/SSZipArchive/aes/brg_endian.h similarity index 100% rename from SSZipArchive/aes/brg_endian.h rename to iOS/SSZipArchive/aes/brg_endian.h diff --git a/SSZipArchive/aes/brg_types.h b/iOS/SSZipArchive/aes/brg_types.h similarity index 100% rename from SSZipArchive/aes/brg_types.h rename to iOS/SSZipArchive/aes/brg_types.h diff --git a/SSZipArchive/aes/entropy.c b/iOS/SSZipArchive/aes/entropy.c similarity index 100% rename from SSZipArchive/aes/entropy.c rename to iOS/SSZipArchive/aes/entropy.c diff --git a/SSZipArchive/aes/entropy.h b/iOS/SSZipArchive/aes/entropy.h similarity index 100% rename from SSZipArchive/aes/entropy.h rename to iOS/SSZipArchive/aes/entropy.h diff --git a/SSZipArchive/aes/fileenc.c b/iOS/SSZipArchive/aes/fileenc.c similarity index 100% rename from SSZipArchive/aes/fileenc.c rename to iOS/SSZipArchive/aes/fileenc.c diff --git a/SSZipArchive/aes/fileenc.h b/iOS/SSZipArchive/aes/fileenc.h similarity index 100% rename from SSZipArchive/aes/fileenc.h rename to iOS/SSZipArchive/aes/fileenc.h diff --git a/SSZipArchive/aes/hmac.c b/iOS/SSZipArchive/aes/hmac.c similarity index 100% rename from SSZipArchive/aes/hmac.c rename to iOS/SSZipArchive/aes/hmac.c diff --git a/SSZipArchive/aes/hmac.h b/iOS/SSZipArchive/aes/hmac.h similarity index 100% rename from SSZipArchive/aes/hmac.h rename to iOS/SSZipArchive/aes/hmac.h diff --git a/SSZipArchive/aes/prng.c b/iOS/SSZipArchive/aes/prng.c similarity index 100% rename from SSZipArchive/aes/prng.c rename to iOS/SSZipArchive/aes/prng.c diff --git a/SSZipArchive/aes/prng.h b/iOS/SSZipArchive/aes/prng.h similarity index 100% rename from SSZipArchive/aes/prng.h rename to iOS/SSZipArchive/aes/prng.h diff --git a/SSZipArchive/aes/pwd2key.c b/iOS/SSZipArchive/aes/pwd2key.c similarity index 100% rename from SSZipArchive/aes/pwd2key.c rename to iOS/SSZipArchive/aes/pwd2key.c diff --git a/SSZipArchive/aes/pwd2key.h b/iOS/SSZipArchive/aes/pwd2key.h similarity index 100% rename from SSZipArchive/aes/pwd2key.h rename to iOS/SSZipArchive/aes/pwd2key.h diff --git a/SSZipArchive/aes/sha1.c b/iOS/SSZipArchive/aes/sha1.c similarity index 100% rename from SSZipArchive/aes/sha1.c rename to iOS/SSZipArchive/aes/sha1.c diff --git a/SSZipArchive/aes/sha1.h b/iOS/SSZipArchive/aes/sha1.h similarity index 100% rename from SSZipArchive/aes/sha1.h rename to iOS/SSZipArchive/aes/sha1.h diff --git a/SSZipArchive/minizip/crypt.h b/iOS/SSZipArchive/minizip/crypt.h similarity index 100% rename from SSZipArchive/minizip/crypt.h rename to iOS/SSZipArchive/minizip/crypt.h diff --git a/SSZipArchive/minizip/ioapi.c b/iOS/SSZipArchive/minizip/ioapi.c similarity index 100% rename from SSZipArchive/minizip/ioapi.c rename to iOS/SSZipArchive/minizip/ioapi.c diff --git a/SSZipArchive/minizip/ioapi.h b/iOS/SSZipArchive/minizip/ioapi.h similarity index 100% rename from SSZipArchive/minizip/ioapi.h rename to iOS/SSZipArchive/minizip/ioapi.h diff --git a/SSZipArchive/minizip/mztools.c b/iOS/SSZipArchive/minizip/mztools.c similarity index 100% rename from SSZipArchive/minizip/mztools.c rename to iOS/SSZipArchive/minizip/mztools.c diff --git a/SSZipArchive/minizip/mztools.h b/iOS/SSZipArchive/minizip/mztools.h similarity index 100% rename from SSZipArchive/minizip/mztools.h rename to iOS/SSZipArchive/minizip/mztools.h diff --git a/SSZipArchive/minizip/unzip.c b/iOS/SSZipArchive/minizip/unzip.c similarity index 100% rename from SSZipArchive/minizip/unzip.c rename to iOS/SSZipArchive/minizip/unzip.c diff --git a/SSZipArchive/minizip/unzip.h b/iOS/SSZipArchive/minizip/unzip.h similarity index 100% rename from SSZipArchive/minizip/unzip.h rename to iOS/SSZipArchive/minizip/unzip.h diff --git a/SSZipArchive/minizip/zip.c b/iOS/SSZipArchive/minizip/zip.c similarity index 100% rename from SSZipArchive/minizip/zip.c rename to iOS/SSZipArchive/minizip/zip.c diff --git a/SSZipArchive/minizip/zip.h b/iOS/SSZipArchive/minizip/zip.h similarity index 100% rename from SSZipArchive/minizip/zip.h rename to iOS/SSZipArchive/minizip/zip.h From 87a4ddd0eb52532c0208684bec9c2a8af3a66fb1 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 15:56:17 -0800 Subject: [PATCH 2/7] remove crypto lib from CodePushPackage.m --- iOS/CodePushPackage.m | 1 - 1 file changed, 1 deletion(-) diff --git a/iOS/CodePushPackage.m b/iOS/CodePushPackage.m index 52d16f9..8285290 100644 --- a/iOS/CodePushPackage.m +++ b/iOS/CodePushPackage.m @@ -1,6 +1,5 @@ #import "CodePush.h" #import "SSZipArchive.h" -#include @implementation CodePushPackage From 797ab25b11a5fbe2edbf6cac582e7b4b10ab77b7 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 15:58:28 -0800 Subject: [PATCH 3/7] whitespaces --- iOS/CodePushPackage.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iOS/CodePushPackage.m b/iOS/CodePushPackage.m index 8285290..5a70817 100644 --- a/iOS/CodePushPackage.m +++ b/iOS/CodePushPackage.m @@ -154,7 +154,7 @@ NSString * const UnzippedFolderName = @"unzipped"; NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:error]; - + return jsonDict; } } @@ -414,7 +414,7 @@ NSString * const UnzippedFolderName = @"unzipped"; doneCallback(); } } - + failCallback:failCallback]; [downloadHandler download:updatePackage[@"downloadUrl"]]; @@ -458,7 +458,7 @@ NSString * const UnzippedFolderName = @"unzipped"; } [info setValue:packageHash forKey:@"currentPackage"]; - + [self updateCurrentPackageInfo:info error:error]; } From fea52827d15ae5d0f6b5666713f9832be3968bfc Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 18:59:05 -0800 Subject: [PATCH 4/7] verify hash after download Android --- .../react/CodePushInvalidUpdateException.java | 4 +- .../codepush/react/CodePushPackage.java | 19 +++-- .../codepush/react/CodePushUpdateUtils.java | 76 ++++++++++++++++++- iOS/CodePushPackage.m | 4 +- iOS/CodePushUtils.m | 2 +- 5 files changed, 93 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java index b678959..d048751 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java @@ -1,7 +1,7 @@ package com.microsoft.codepush.react; public class CodePushInvalidUpdateException extends RuntimeException { - public CodePushInvalidUpdateException() { - super("Update is invalid - no files with extension .bundle, .js or .jsbundle were found in the update package."); + public CodePushInvalidUpdateException(String message) { + super(message); } } diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java index 3a9b550..9179813 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java @@ -153,8 +153,9 @@ public class CodePushPackage { public void downloadPackage(Context applicationContext, ReadableMap updatePackage, DownloadProgressCallback progressCallback) throws IOException { - - String newPackageFolderPath = getPackageFolderPath(CodePushUtils.tryGetString(updatePackage, PACKAGE_HASH_KEY)); + String newPackageHash = CodePushUtils.tryGetString(updatePackage, PACKAGE_HASH_KEY); + String newPackageFolderPath = getPackageFolderPath(newPackageHash); + String newPackageMetadataPath = CodePushUtils.appendPathComponent(newPackageFolderPath, PACKAGE_FILE_NAME); if (FileUtils.fileAtPathExists(newPackageFolderPath)) { // This removes any stale data in newPackageFolderPath that could have been left // uncleared due to a crash or error during the download or install process. @@ -232,6 +233,8 @@ public class CodePushPackage { if (FileUtils.fileAtPathExists(diffManifestFilePath)) { String currentPackageFolderPath = getCurrentPackageFolderPath(); CodePushUpdateUtils.copyNecessaryFilesFromCurrentPackage(diffManifestFilePath, currentPackageFolderPath, newPackageFolderPath); + File diffManifestFile = new File(diffManifestFilePath); + diffManifestFile.delete(); } FileUtils.copyDirectoryContents(unzippedFolderPath, newPackageFolderPath); @@ -242,8 +245,15 @@ public class CodePushPackage { String relativeBundlePath = CodePushUpdateUtils.findJSBundleInUpdateContents(newPackageFolderPath); if (relativeBundlePath == null) { - throw new CodePushInvalidUpdateException(); + throw new CodePushInvalidUpdateException("Update is invalid - no files with extension .bundle, .js or .jsbundle were found in the update package."); } else { + if (FileUtils.fileAtPathExists(newPackageMetadataPath)) { + File metadataFileFromOldUpdate = new File(newPackageMetadataPath); + metadataFileFromOldUpdate.delete(); + } + + CodePushUpdateUtils.verifyHashForZipUpdate(newPackageFolderPath, newPackageHash); + JSONObject updatePackageJSON = CodePushUtils.convertReadableToJsonObject(updatePackage); try { updatePackageJSON.put(RELATIVE_BUNDLE_PATH_KEY, relativeBundlePath); @@ -261,8 +271,7 @@ public class CodePushPackage { } // Save metadata to the folder. - String bundlePath = CodePushUtils.appendPathComponent(newPackageFolderPath, PACKAGE_FILE_NAME); - CodePushUtils.writeReadableMapToFile(updatePackage, bundlePath); + CodePushUtils.writeReadableMapToFile(updatePackage, newPackageMetadataPath); } public void installPackage(ReadableMap updatePackage, boolean removePendingUpdate) throws IOException { diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java index 8e43847..f38b1c8 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java @@ -3,11 +3,66 @@ package com.microsoft.codepush.react; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableMap; +import org.json.JSONArray; + +import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; public class CodePushUpdateUtils { + private static void addContentsOfFolderToManifest(String folderPath, String pathPrefix, ArrayList manifest) { + File folder = new File(folderPath); + File[] folderFiles = folder.listFiles(); + for (File file : folderFiles) { + String fullFilePath = file.getAbsolutePath(); + String relativePath = (pathPrefix.isEmpty() ? "" : (pathPrefix + "/")) + file.getName(); + if (file.isDirectory()) { + addContentsOfFolderToManifest(fullFilePath, relativePath, manifest); + } else { + try { + // Substring 1 because appendPathComponent creates a "/" prefix to the relativePath. + manifest.add(relativePath + ":" + computeHash(new FileInputStream(file))); + } catch (FileNotFoundException e) { + // Should not happen. + throw new CodePushUnknownException("Unable to compute hash of update contents.", e); + } + } + } + } + + private static String computeHash(InputStream dataStream) { + MessageDigest messageDigest = null; + DigestInputStream digestInputStream = null; + try { + messageDigest = MessageDigest.getInstance("SHA-256"); + digestInputStream = new DigestInputStream(dataStream, messageDigest); + byte[] byteBuffer = new byte[1024 * 8]; + while (digestInputStream.read(byteBuffer) != -1); + } catch (NoSuchAlgorithmException | IOException e) { + // Should not happen. + throw new CodePushUnknownException("Unable to compute hash of update contents.", e); + } finally { + try { + if (digestInputStream != null) digestInputStream.close(); + if (dataStream != null) dataStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + byte[] hash = messageDigest.digest(); + return String.format("%064x", new java.math.BigInteger(1, hash)); + } + public static void copyNecessaryFilesFromCurrentPackage(String diffManifestFilePath, String currentPackageFolderPath, String newPackageFolderPath) throws IOException{ FileUtils.copyDirectoryContents(currentPackageFolderPath, newPackageFolderPath); WritableMap diffManifest = CodePushUtils.getWritableMapFromFile(diffManifestFilePath); @@ -15,7 +70,9 @@ public class CodePushUpdateUtils { for (int i = 0; i < deletedFiles.size(); i++) { String fileNameToDelete = deletedFiles.getString(i); File fileToDelete = new File(newPackageFolderPath, fileNameToDelete); - FileUtils.deleteFileOrFolderSilently(fileToDelete); + if (fileToDelete.exists()) { + fileToDelete.delete(); + } } } @@ -43,4 +100,21 @@ public class CodePushUpdateUtils { return null; } + + public static void verifyHashForZipUpdate(String folderPath, String expectedHash) { + ArrayList updateContentsManifest = new ArrayList(); + addContentsOfFolderToManifest(folderPath, "", updateContentsManifest); + Collections.sort(updateContentsManifest); + JSONArray updateContentsJSONArray = new JSONArray(); + for (String manifestEntry : updateContentsManifest) { + updateContentsJSONArray.put(manifestEntry); + } + + // The JSON serialization turns path separators into "\/", e.g. "CodePush\/assets\/image.png" + String updateContentsManifestString = updateContentsJSONArray.toString().replace("\\/", "/"); + String updateContentsManifestHash = computeHash(new ByteArrayInputStream(updateContentsManifestString.getBytes())); + if (!expectedHash.equals(updateContentsManifestHash)) { + throw new CodePushInvalidUpdateException("The update contents failed the data integrity check."); + } + } } diff --git a/iOS/CodePushPackage.m b/iOS/CodePushPackage.m index 5a70817..eac0371 100644 --- a/iOS/CodePushPackage.m +++ b/iOS/CodePushPackage.m @@ -296,9 +296,7 @@ NSString * const UnzippedFolderName = @"unzipped"; return; } } - } - - if ([[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]) { + [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath error:&error]; if (error) { diff --git a/iOS/CodePushUtils.m b/iOS/CodePushUtils.m index c187862..fc05b21 100644 --- a/iOS/CodePushUtils.m +++ b/iOS/CodePushUtils.m @@ -146,7 +146,7 @@ error:error]; NSString *updateContentsManifestString = [[NSString alloc] initWithData:updateContentsManifestData encoding:NSUTF8StringEncoding]; - // The JSON serialization turns path seperators into "\/", e.g. "CodePush\/assets\/image.png" + // The JSON serialization turns path separators into "\/", e.g. "CodePush\/assets\/image.png" updateContentsManifestString = [updateContentsManifestString stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; NSString *updateContentsManifestHash = [self computeHash:[NSData dataWithBytes:updateContentsManifestString.UTF8String length:updateContentsManifestString.length]]; From f590b1c294a676a7acf034907c1409760954caaf Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 23:48:14 -0800 Subject: [PATCH 5/7] feedback --- .../CodePushDemoApp.xcodeproj/project.pbxproj | 62 +++++++++---------- .../codepush/react/CodePushUpdateUtils.java | 4 +- .../CodePush.xcodeproj}/project.pbxproj | 34 +++++----- .../contents.xcworkspacedata | 0 {iOS => ios/CodePush}/CodePush.h | 7 +-- {iOS => ios/CodePush}/CodePush.m | 0 {iOS => ios/CodePush}/CodePushConfig.m | 0 .../CodePush}/CodePushDownloadHandler.m | 0 {iOS => ios/CodePush}/CodePushPackage.m | 51 ++++++++------- .../CodePush}/CodePushTelemetryManager.m | 0 .../CodePush/CodePushUpdateUtils.m | 2 +- .../RCTConvert+CodePushInstallMode.m | 0 {iOS => ios/CodePush}/SSZipArchive/Common.h | 0 {iOS => ios/CodePush}/SSZipArchive/README.md | 0 .../CodePush}/SSZipArchive/SSZipArchive.h | 0 .../CodePush}/SSZipArchive/SSZipArchive.m | 0 {iOS => ios/CodePush}/SSZipArchive/aes/aes.h | 0 .../CodePush}/SSZipArchive/aes/aes_via_ace.h | 0 .../CodePush}/SSZipArchive/aes/aescrypt.c | 0 .../CodePush}/SSZipArchive/aes/aeskey.c | 0 .../CodePush}/SSZipArchive/aes/aesopt.h | 0 .../CodePush}/SSZipArchive/aes/aestab.c | 0 .../CodePush}/SSZipArchive/aes/aestab.h | 0 .../CodePush}/SSZipArchive/aes/brg_endian.h | 0 .../CodePush}/SSZipArchive/aes/brg_types.h | 0 .../CodePush}/SSZipArchive/aes/entropy.c | 0 .../CodePush}/SSZipArchive/aes/entropy.h | 0 .../CodePush}/SSZipArchive/aes/fileenc.c | 0 .../CodePush}/SSZipArchive/aes/fileenc.h | 0 {iOS => ios/CodePush}/SSZipArchive/aes/hmac.c | 0 {iOS => ios/CodePush}/SSZipArchive/aes/hmac.h | 0 {iOS => ios/CodePush}/SSZipArchive/aes/prng.c | 0 {iOS => ios/CodePush}/SSZipArchive/aes/prng.h | 0 .../CodePush}/SSZipArchive/aes/pwd2key.c | 0 .../CodePush}/SSZipArchive/aes/pwd2key.h | 0 {iOS => ios/CodePush}/SSZipArchive/aes/sha1.c | 0 {iOS => ios/CodePush}/SSZipArchive/aes/sha1.h | 0 .../CodePush}/SSZipArchive/minizip/crypt.h | 0 .../CodePush}/SSZipArchive/minizip/ioapi.c | 0 .../CodePush}/SSZipArchive/minizip/ioapi.h | 0 .../CodePush}/SSZipArchive/minizip/mztools.c | 0 .../CodePush}/SSZipArchive/minizip/mztools.h | 0 .../CodePush}/SSZipArchive/minizip/unzip.c | 0 .../CodePush}/SSZipArchive/minizip/unzip.h | 0 .../CodePush}/SSZipArchive/minizip/zip.c | 0 .../CodePush}/SSZipArchive/minizip/zip.h | 0 46 files changed, 78 insertions(+), 82 deletions(-) rename {CodePush.xcodeproj => ios/CodePush.xcodeproj}/project.pbxproj (93%) rename {CodePush.xcodeproj => ios/CodePush.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename {iOS => ios/CodePush}/CodePush.h (92%) rename {iOS => ios/CodePush}/CodePush.m (100%) rename {iOS => ios/CodePush}/CodePushConfig.m (100%) rename {iOS => ios/CodePush}/CodePushDownloadHandler.m (100%) rename {iOS => ios/CodePush}/CodePushPackage.m (91%) rename {iOS => ios/CodePush}/CodePushTelemetryManager.m (100%) rename iOS/CodePushUtils.m => ios/CodePush/CodePushUpdateUtils.m (99%) rename {iOS => ios/CodePush}/RCTConvert+CodePushInstallMode.m (100%) rename {iOS => ios/CodePush}/SSZipArchive/Common.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/README.md (100%) rename {iOS => ios/CodePush}/SSZipArchive/SSZipArchive.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/SSZipArchive.m (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aes.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aes_via_ace.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aescrypt.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aeskey.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aesopt.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aestab.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/aestab.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/brg_endian.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/brg_types.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/entropy.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/entropy.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/fileenc.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/fileenc.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/hmac.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/hmac.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/prng.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/prng.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/pwd2key.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/pwd2key.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/sha1.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/aes/sha1.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/crypt.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/ioapi.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/ioapi.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/mztools.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/mztools.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/unzip.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/unzip.h (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/zip.c (100%) rename {iOS => ios/CodePush}/SSZipArchive/minizip/zip.h (100%) diff --git a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj index 2e8d08a..1ee3b8b 100644 --- a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj +++ b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj @@ -21,13 +21,12 @@ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 542D39D41C22CED700D4B648 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 81551E0F1B3B427200F5B9F1 /* libCodePush.a */; }; + 540D20251C76EA0400D6EF41 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 540D20241C76E4D300D6EF41 /* libCodePush.a */; }; 544161591B8BCA81000D9E25 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 5451ACBA1B86A5B600E2A7DF /* CheckForUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5451ACB81B86A5B600E2A7DF /* CheckForUpdateTests.m */; }; 5451ACEC1B86E40A00E2A7DF /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5451ACEB1B86E34300E2A7DF /* libRCTTest.a */; }; 54D774BA1B87DAF800F2ABF8 /* InstallUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54D774B91B87DAF800F2ABF8 /* InstallUpdateTests.m */; }; 54F5F2B41BF6B45D007C3CEA /* DownloadProgressTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 54F5F2B31BF6B45D007C3CEA /* DownloadProgressTests.m */; }; - 81551E1B1B3B428000F5B9F1 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 81551E0F1B3B427200F5B9F1 /* libCodePush.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -101,6 +100,13 @@ remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; remoteInfo = React; }; + 540D20231C76E4D300D6EF41 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 81551E0A1B3B427200F5B9F1 /* CodePush.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = CodePush; + }; 5451ACEA1B86E34300E2A7DF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5451ACE61B86E34300E2A7DF /* RCTTest.xcodeproj */; @@ -115,13 +121,6 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RCTLinking; }; - 81551E0E1B3B427200F5B9F1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 81551E0A1B3B427200F5B9F1 /* CodePush.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = CodePush; - }; 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; @@ -155,7 +154,7 @@ 54D774B91B87DAF800F2ABF8 /* InstallUpdateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstallUpdateTests.m; sourceTree = ""; }; 54F5F2B31BF6B45D007C3CEA /* DownloadProgressTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DownloadProgressTests.m; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; - 81551E0A1B3B427200F5B9F1 /* CodePush.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CodePush.xcodeproj; path = ../../../CodePush.xcodeproj; sourceTree = ""; }; + 81551E0A1B3B427200F5B9F1 /* CodePush.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CodePush.xcodeproj; path = ../../../ios/CodePush.xcodeproj; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -164,7 +163,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 542D39D41C22CED700D4B648 /* libCodePush.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -172,6 +170,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 540D20251C76EA0400D6EF41 /* libCodePush.a in Frameworks */, 544161591B8BCA81000D9E25 /* libRCTText.a in Frameworks */, 5451ACEC1B86E40A00E2A7DF /* libRCTTest.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, @@ -184,7 +183,6 @@ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, - 81551E1B1B3B428000F5B9F1 /* libCodePush.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -295,6 +293,14 @@ name = Products; sourceTree = ""; }; + 540D20201C76E4D300D6EF41 /* Products */ = { + isa = PBXGroup; + children = ( + 540D20241C76E4D300D6EF41 /* libCodePush.a */, + ); + name = Products; + sourceTree = ""; + }; 5451ACE71B86E34300E2A7DF /* Products */ = { isa = PBXGroup; children = ( @@ -311,14 +317,6 @@ name = Products; sourceTree = ""; }; - 81551E0B1B3B427200F5B9F1 /* Products */ = { - isa = PBXGroup; - children = ( - 81551E0F1B3B427200F5B9F1 /* libCodePush.a */, - ); - name = Products; - sourceTree = ""; - }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( @@ -435,7 +433,7 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = 81551E0B1B3B427200F5B9F1 /* Products */; + ProductGroup = 540D20201C76E4D300D6EF41 /* Products */; ProjectRef = 81551E0A1B3B427200F5B9F1 /* CodePush.xcodeproj */; }, { @@ -559,6 +557,13 @@ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 540D20241C76E4D300D6EF41 /* libCodePush.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libCodePush.a; + remoteRef = 540D20231C76E4D300D6EF41 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 5451ACEB1B86E34300E2A7DF /* libRCTTest.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -573,13 +578,6 @@ remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 81551E0F1B3B427200F5B9F1 /* libCodePush.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libCodePush.a; - remoteRef = 81551E0E1B3B427200F5B9F1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -684,7 +682,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../iOS/**", + "$(SRCROOT)/../../../ios/**", "$(SRCROOT)/../node_modules/react-native/Libraries/Text/", ); INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist; @@ -708,7 +706,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../iOS/**", + "$(SRCROOT)/../../../ios/**", "$(SRCROOT)/../node_modules/react-native/Libraries/Text/", ); INFOPLIST_FILE = ../CodePushDemoAppTests/Info.plist; @@ -727,7 +725,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../iOS/**", + "$(SRCROOT)/../../../ios/**", ); INFOPLIST_FILE = "$(SRCROOT)/CodePushDemoApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -747,7 +745,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", - "$(SRCROOT)/../../../iOS/**", + "$(SRCROOT)/../../../ios/**", ); INFOPLIST_FILE = "$(SRCROOT)/CodePushDemoApp/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java index f38b1c8..fc97fa6 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java @@ -1,5 +1,7 @@ package com.microsoft.codepush.react; +import android.util.Base64; + import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableMap; @@ -60,7 +62,7 @@ public class CodePushUpdateUtils { } byte[] hash = messageDigest.digest(); - return String.format("%064x", new java.math.BigInteger(1, hash)); + return Base64.encodeToString(hash, 0, hash.length, 0); } public static void copyNecessaryFilesFromCurrentPackage(String diffManifestFilePath, String currentPackageFolderPath, String newPackageFolderPath) throws IOException{ diff --git a/CodePush.xcodeproj/project.pbxproj b/ios/CodePush.xcodeproj/project.pbxproj similarity index 93% rename from CodePush.xcodeproj/project.pbxproj rename to ios/CodePush.xcodeproj/project.pbxproj index fcf5bcf..3eee8ce 100644 --- a/CodePush.xcodeproj/project.pbxproj +++ b/ios/CodePush.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 13BE3DEE1AC21097009241FE /* CodePush.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.m */; }; 1B23B9141BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */; }; - 540D20121C7684FE00D6EF41 /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 540D20111C7684FE00D6EF41 /* CodePushUtils.m */; }; + 540D20121C7684FE00D6EF41 /* CodePushUpdateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */; }; 5421FE311C58AD5A00986A55 /* CodePushTelemetryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */; }; 54A0026C1C0E2880004C3CEC /* aescrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A0024C1C0E2880004C3CEC /* aescrypt.c */; }; 54A0026D1C0E2880004C3CEC /* aeskey.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A0024D1C0E2880004C3CEC /* aeskey.c */; }; @@ -44,11 +44,11 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCodePush.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodePush.h; path = iOS/CodePush.h; sourceTree = ""; }; - 13BE3DED1AC21097009241FE /* CodePush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePush.m; path = iOS/CodePush.m; sourceTree = ""; }; - 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+CodePushInstallMode.m"; path = "iOS/RCTConvert+CodePushInstallMode.m"; sourceTree = ""; }; - 540D20111C7684FE00D6EF41 /* CodePushUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushUtils.m; path = iOS/CodePushUtils.m; sourceTree = ""; }; - 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushTelemetryManager.m; path = iOS/CodePushTelemetryManager.m; sourceTree = ""; }; + 13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodePush.h; path = CodePush/CodePush.h; sourceTree = ""; }; + 13BE3DED1AC21097009241FE /* CodePush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePush.m; path = CodePush/CodePush.m; sourceTree = ""; }; + 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+CodePushInstallMode.m"; path = "CodePush/RCTConvert+CodePushInstallMode.m"; sourceTree = ""; }; + 540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushUpdateUtils.m; path = CodePush/CodePushUpdateUtils.m; sourceTree = ""; }; + 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushTelemetryManager.m; path = CodePush/CodePushTelemetryManager.m; sourceTree = ""; }; 54A0024A1C0E2880004C3CEC /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; 54A0024B1C0E2880004C3CEC /* aes_via_ace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes_via_ace.h; sourceTree = ""; }; 54A0024C1C0E2880004C3CEC /* aescrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aescrypt.c; sourceTree = ""; }; @@ -82,9 +82,9 @@ 54A002691C0E2880004C3CEC /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; 54A0026A1C0E2880004C3CEC /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchive.h; sourceTree = ""; }; 54A0026B1C0E2880004C3CEC /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchive.m; sourceTree = ""; }; - 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushDownloadHandler.m; path = iOS/CodePushDownloadHandler.m; sourceTree = ""; }; - 810D4E6C1B96935000B397E9 /* CodePushPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushPackage.m; path = iOS/CodePushPackage.m; sourceTree = ""; }; - 81D51F391B6181C2000DA084 /* CodePushConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushConfig.m; path = iOS/CodePushConfig.m; sourceTree = ""; }; + 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushDownloadHandler.m; path = CodePush/CodePushDownloadHandler.m; sourceTree = ""; }; + 810D4E6C1B96935000B397E9 /* CodePushPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushPackage.m; path = CodePush/CodePushPackage.m; sourceTree = ""; }; + 81D51F391B6181C2000DA084 /* CodePushConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushConfig.m; path = CodePush/CodePushConfig.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -116,7 +116,7 @@ 54A0026B1C0E2880004C3CEC /* SSZipArchive.m */, ); name = SSZipArchive; - path = iOS/SSZipArchive; + path = CodePush/SSZipArchive; sourceTree = ""; }; 54A002491C0E2880004C3CEC /* aes */ = { @@ -172,7 +172,7 @@ 810D4E6C1B96935000B397E9 /* CodePushPackage.m */, 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */, 81D51F391B6181C2000DA084 /* CodePushConfig.m */, - 540D20111C7684FE00D6EF41 /* CodePushUtils.m */, + 540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */, 13BE3DEC1AC21097009241FE /* CodePush.h */, 13BE3DED1AC21097009241FE /* CodePush.m */, 134814211AA4EA7D00B7C361 /* Products */, @@ -236,7 +236,7 @@ buildActionMask = 2147483647; files = ( 54A0026D1C0E2880004C3CEC /* aeskey.c in Sources */, - 540D20121C7684FE00D6EF41 /* CodePushUtils.m in Sources */, + 540D20121C7684FE00D6EF41 /* CodePushUpdateUtils.m in Sources */, 54A0026E1C0E2880004C3CEC /* aestab.c in Sources */, 54A002761C0E2880004C3CEC /* mztools.c in Sources */, 54A002781C0E2880004C3CEC /* zip.c in Sources */, @@ -342,9 +342,8 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - "$(SRCROOT)/Examples/CodePushDemoApp/node_modules/react-native/React/**", - "$(SRCROOT)/../react-native/React/**", + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../Examples/CodePushDemoApp/node_modules/react-native/React/**", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = ( @@ -362,9 +361,8 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - "$(SRCROOT)/Examples/CodePushDemoApp/node_modules/react-native/React/**", - "$(SRCROOT)/../react-native/React/**", + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../Examples/CodePushDemoApp/node_modules/react-native/React/**", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = ( diff --git a/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to ios/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/iOS/CodePush.h b/ios/CodePush/CodePush.h similarity index 92% rename from iOS/CodePush.h rename to ios/CodePush/CodePush.h index 4920700..b77a531 100644 --- a/iOS/CodePush.h +++ b/ios/CodePush/CodePush.h @@ -104,13 +104,8 @@ failCallback:(void (^)(NSError *err))failCallback; @end -@interface CodePushUtils : NSObject +@interface CodePushUpdateUtils : NSObject -+ (void)addContentsOfFolderToManifest:(NSString *)folderPath - pathPrefix:(NSString *)pathPrefix - manifest:(NSMutableArray *)manifest - error:(NSError **)error; -+ (NSString *)computeHash:(NSData *)inputData; + (void)copyEntriesInFolder:(NSString *)sourceFolder destFolder:(NSString *)destFolder error:(NSError **)error; diff --git a/iOS/CodePush.m b/ios/CodePush/CodePush.m similarity index 100% rename from iOS/CodePush.m rename to ios/CodePush/CodePush.m diff --git a/iOS/CodePushConfig.m b/ios/CodePush/CodePushConfig.m similarity index 100% rename from iOS/CodePushConfig.m rename to ios/CodePush/CodePushConfig.m diff --git a/iOS/CodePushDownloadHandler.m b/ios/CodePush/CodePushDownloadHandler.m similarity index 100% rename from iOS/CodePushDownloadHandler.m rename to ios/CodePush/CodePushDownloadHandler.m diff --git a/iOS/CodePushPackage.m b/ios/CodePush/CodePushPackage.m similarity index 91% rename from iOS/CodePushPackage.m rename to ios/CodePush/CodePushPackage.m index eac0371..929f3d3 100644 --- a/iOS/CodePushPackage.m +++ b/ios/CodePush/CodePushPackage.m @@ -203,15 +203,15 @@ NSString * const UnzippedFolderName = @"unzipped"; doneCallback:(void (^)())doneCallback failCallback:(void (^)(NSError *err))failCallback { - NSString *newPackageHash = updatePackage[@"packageHash"]; - NSString *newPackageFolderPath = [self getPackageFolderPath:newPackageHash]; - NSString *newPackageMetadataPath = [newPackageFolderPath stringByAppendingPathComponent:@"app.json"]; + NSString *newUpdateHash = updatePackage[@"packageHash"]; + NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash]; + NSString *newUpdateMetadataPath = [newUpdateFolderPath stringByAppendingPathComponent:@"app.json"]; NSError *error; - if ([[NSFileManager defaultManager] fileExistsAtPath:newPackageFolderPath]) { + if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateFolderPath]) { // This removes any stale data in newPackageFolderPath that could have been left // uncleared due to a crash or error during the download or install process. - [[NSFileManager defaultManager] removeItemAtPath:newPackageFolderPath + [[NSFileManager defaultManager] removeItemAtPath:newUpdateFolderPath error:&error]; } else if (![[NSFileManager defaultManager] fileExistsAtPath:[self getCodePushPath]]) { [[NSFileManager defaultManager] createDirectoryAtPath:[self getCodePushPath] @@ -225,7 +225,7 @@ NSString * const UnzippedFolderName = @"unzipped"; } NSString *downloadFilePath = [self getDownloadFilePath]; - NSString *bundleFilePath = [newPackageFolderPath stringByAppendingPathComponent:UpdateBundleFileName]; + NSString *bundleFilePath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateBundleFileName]; CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc] init:downloadFilePath @@ -267,7 +267,7 @@ NSString * const UnzippedFolderName = @"unzipped"; } [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath - toPath:newPackageFolderPath + toPath:newUpdateFolderPath error:&error]; if (error) { failCallback(error); @@ -289,11 +289,14 @@ NSString * const UnzippedFolderName = @"unzipped"; error:&error]; NSArray *deletedFiles = manifestJSON[@"deletedFiles"]; for (NSString *deletedFileName in deletedFiles) { - [[NSFileManager defaultManager] removeItemAtPath:[newPackageFolderPath stringByAppendingPathComponent:deletedFileName] - error:&error]; - if (error) { - failCallback(error); - return; + NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName]; + if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) { + [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath + error:&error]; + if (error) { + failCallback(error); + return; + } } } @@ -305,8 +308,8 @@ NSString * const UnzippedFolderName = @"unzipped"; } } - [CodePushUtils copyEntriesInFolder:unzippedFolderPath - destFolder:newPackageFolderPath + [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath + destFolder:newUpdateFolderPath error:&error]; if (error) { failCallback(error); @@ -320,15 +323,15 @@ NSString * const UnzippedFolderName = @"unzipped"; nonFailingError = nil; } - NSString *relativeBundlePath = [CodePushUtils findMainBundleInFolder:newPackageFolderPath - error:&error]; + NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath + error:&error]; if (error) { failCallback(error); return; } if (relativeBundlePath) { - NSString *absoluteBundlePath = [newPackageFolderPath stringByAppendingPathComponent:relativeBundlePath]; + NSString *absoluteBundlePath = [newUpdateFolderPath stringByAppendingPathComponent:relativeBundlePath]; NSDictionary *bundleFileAttributes = [[[NSFileManager defaultManager] attributesOfItemAtPath:absoluteBundlePath error:&error] mutableCopy]; if (error) { failCallback(error); @@ -356,8 +359,8 @@ NSString * const UnzippedFolderName = @"unzipped"; return; } - if ([[NSFileManager defaultManager] fileExistsAtPath:newPackageMetadataPath]) { - [[NSFileManager defaultManager] removeItemAtPath:newPackageMetadataPath + if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) { + [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath error:&error]; if (error) { failCallback(error); @@ -365,9 +368,9 @@ NSString * const UnzippedFolderName = @"unzipped"; } } - if (![CodePushUtils verifyHashForZipUpdate:newPackageFolderPath - expectedHash:newPackageHash - error:&error]) { + if (![CodePushUpdateUtils verifyHashForZipUpdate:newUpdateFolderPath + expectedHash:newUpdateHash + error:&error]) { if (error) { failCallback(error); return; @@ -383,7 +386,7 @@ NSString * const UnzippedFolderName = @"unzipped"; return; } } else { - [[NSFileManager defaultManager] createDirectoryAtPath:newPackageFolderPath + [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath withIntermediateDirectories:YES attributes:nil error:&error]; @@ -402,7 +405,7 @@ NSString * const UnzippedFolderName = @"unzipped"; NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData encoding:NSUTF8StringEncoding]; - [packageJsonString writeToFile:newPackageMetadataPath + [packageJsonString writeToFile:newUpdateMetadataPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; diff --git a/iOS/CodePushTelemetryManager.m b/ios/CodePush/CodePushTelemetryManager.m similarity index 100% rename from iOS/CodePushTelemetryManager.m rename to ios/CodePush/CodePushTelemetryManager.m diff --git a/iOS/CodePushUtils.m b/ios/CodePush/CodePushUpdateUtils.m similarity index 99% rename from iOS/CodePushUtils.m rename to ios/CodePush/CodePushUpdateUtils.m index fc05b21..8a2e23d 100644 --- a/iOS/CodePushUtils.m +++ b/ios/CodePush/CodePushUpdateUtils.m @@ -1,7 +1,7 @@ #import "CodePush.h" #include -@implementation CodePushUtils +@implementation CodePushUpdateUtils + (void)addContentsOfFolderToManifest:(NSString *)folderPath pathPrefix:(NSString *)pathPrefix diff --git a/iOS/RCTConvert+CodePushInstallMode.m b/ios/CodePush/RCTConvert+CodePushInstallMode.m similarity index 100% rename from iOS/RCTConvert+CodePushInstallMode.m rename to ios/CodePush/RCTConvert+CodePushInstallMode.m diff --git a/iOS/SSZipArchive/Common.h b/ios/CodePush/SSZipArchive/Common.h similarity index 100% rename from iOS/SSZipArchive/Common.h rename to ios/CodePush/SSZipArchive/Common.h diff --git a/iOS/SSZipArchive/README.md b/ios/CodePush/SSZipArchive/README.md similarity index 100% rename from iOS/SSZipArchive/README.md rename to ios/CodePush/SSZipArchive/README.md diff --git a/iOS/SSZipArchive/SSZipArchive.h b/ios/CodePush/SSZipArchive/SSZipArchive.h similarity index 100% rename from iOS/SSZipArchive/SSZipArchive.h rename to ios/CodePush/SSZipArchive/SSZipArchive.h diff --git a/iOS/SSZipArchive/SSZipArchive.m b/ios/CodePush/SSZipArchive/SSZipArchive.m similarity index 100% rename from iOS/SSZipArchive/SSZipArchive.m rename to ios/CodePush/SSZipArchive/SSZipArchive.m diff --git a/iOS/SSZipArchive/aes/aes.h b/ios/CodePush/SSZipArchive/aes/aes.h similarity index 100% rename from iOS/SSZipArchive/aes/aes.h rename to ios/CodePush/SSZipArchive/aes/aes.h diff --git a/iOS/SSZipArchive/aes/aes_via_ace.h b/ios/CodePush/SSZipArchive/aes/aes_via_ace.h similarity index 100% rename from iOS/SSZipArchive/aes/aes_via_ace.h rename to ios/CodePush/SSZipArchive/aes/aes_via_ace.h diff --git a/iOS/SSZipArchive/aes/aescrypt.c b/ios/CodePush/SSZipArchive/aes/aescrypt.c similarity index 100% rename from iOS/SSZipArchive/aes/aescrypt.c rename to ios/CodePush/SSZipArchive/aes/aescrypt.c diff --git a/iOS/SSZipArchive/aes/aeskey.c b/ios/CodePush/SSZipArchive/aes/aeskey.c similarity index 100% rename from iOS/SSZipArchive/aes/aeskey.c rename to ios/CodePush/SSZipArchive/aes/aeskey.c diff --git a/iOS/SSZipArchive/aes/aesopt.h b/ios/CodePush/SSZipArchive/aes/aesopt.h similarity index 100% rename from iOS/SSZipArchive/aes/aesopt.h rename to ios/CodePush/SSZipArchive/aes/aesopt.h diff --git a/iOS/SSZipArchive/aes/aestab.c b/ios/CodePush/SSZipArchive/aes/aestab.c similarity index 100% rename from iOS/SSZipArchive/aes/aestab.c rename to ios/CodePush/SSZipArchive/aes/aestab.c diff --git a/iOS/SSZipArchive/aes/aestab.h b/ios/CodePush/SSZipArchive/aes/aestab.h similarity index 100% rename from iOS/SSZipArchive/aes/aestab.h rename to ios/CodePush/SSZipArchive/aes/aestab.h diff --git a/iOS/SSZipArchive/aes/brg_endian.h b/ios/CodePush/SSZipArchive/aes/brg_endian.h similarity index 100% rename from iOS/SSZipArchive/aes/brg_endian.h rename to ios/CodePush/SSZipArchive/aes/brg_endian.h diff --git a/iOS/SSZipArchive/aes/brg_types.h b/ios/CodePush/SSZipArchive/aes/brg_types.h similarity index 100% rename from iOS/SSZipArchive/aes/brg_types.h rename to ios/CodePush/SSZipArchive/aes/brg_types.h diff --git a/iOS/SSZipArchive/aes/entropy.c b/ios/CodePush/SSZipArchive/aes/entropy.c similarity index 100% rename from iOS/SSZipArchive/aes/entropy.c rename to ios/CodePush/SSZipArchive/aes/entropy.c diff --git a/iOS/SSZipArchive/aes/entropy.h b/ios/CodePush/SSZipArchive/aes/entropy.h similarity index 100% rename from iOS/SSZipArchive/aes/entropy.h rename to ios/CodePush/SSZipArchive/aes/entropy.h diff --git a/iOS/SSZipArchive/aes/fileenc.c b/ios/CodePush/SSZipArchive/aes/fileenc.c similarity index 100% rename from iOS/SSZipArchive/aes/fileenc.c rename to ios/CodePush/SSZipArchive/aes/fileenc.c diff --git a/iOS/SSZipArchive/aes/fileenc.h b/ios/CodePush/SSZipArchive/aes/fileenc.h similarity index 100% rename from iOS/SSZipArchive/aes/fileenc.h rename to ios/CodePush/SSZipArchive/aes/fileenc.h diff --git a/iOS/SSZipArchive/aes/hmac.c b/ios/CodePush/SSZipArchive/aes/hmac.c similarity index 100% rename from iOS/SSZipArchive/aes/hmac.c rename to ios/CodePush/SSZipArchive/aes/hmac.c diff --git a/iOS/SSZipArchive/aes/hmac.h b/ios/CodePush/SSZipArchive/aes/hmac.h similarity index 100% rename from iOS/SSZipArchive/aes/hmac.h rename to ios/CodePush/SSZipArchive/aes/hmac.h diff --git a/iOS/SSZipArchive/aes/prng.c b/ios/CodePush/SSZipArchive/aes/prng.c similarity index 100% rename from iOS/SSZipArchive/aes/prng.c rename to ios/CodePush/SSZipArchive/aes/prng.c diff --git a/iOS/SSZipArchive/aes/prng.h b/ios/CodePush/SSZipArchive/aes/prng.h similarity index 100% rename from iOS/SSZipArchive/aes/prng.h rename to ios/CodePush/SSZipArchive/aes/prng.h diff --git a/iOS/SSZipArchive/aes/pwd2key.c b/ios/CodePush/SSZipArchive/aes/pwd2key.c similarity index 100% rename from iOS/SSZipArchive/aes/pwd2key.c rename to ios/CodePush/SSZipArchive/aes/pwd2key.c diff --git a/iOS/SSZipArchive/aes/pwd2key.h b/ios/CodePush/SSZipArchive/aes/pwd2key.h similarity index 100% rename from iOS/SSZipArchive/aes/pwd2key.h rename to ios/CodePush/SSZipArchive/aes/pwd2key.h diff --git a/iOS/SSZipArchive/aes/sha1.c b/ios/CodePush/SSZipArchive/aes/sha1.c similarity index 100% rename from iOS/SSZipArchive/aes/sha1.c rename to ios/CodePush/SSZipArchive/aes/sha1.c diff --git a/iOS/SSZipArchive/aes/sha1.h b/ios/CodePush/SSZipArchive/aes/sha1.h similarity index 100% rename from iOS/SSZipArchive/aes/sha1.h rename to ios/CodePush/SSZipArchive/aes/sha1.h diff --git a/iOS/SSZipArchive/minizip/crypt.h b/ios/CodePush/SSZipArchive/minizip/crypt.h similarity index 100% rename from iOS/SSZipArchive/minizip/crypt.h rename to ios/CodePush/SSZipArchive/minizip/crypt.h diff --git a/iOS/SSZipArchive/minizip/ioapi.c b/ios/CodePush/SSZipArchive/minizip/ioapi.c similarity index 100% rename from iOS/SSZipArchive/minizip/ioapi.c rename to ios/CodePush/SSZipArchive/minizip/ioapi.c diff --git a/iOS/SSZipArchive/minizip/ioapi.h b/ios/CodePush/SSZipArchive/minizip/ioapi.h similarity index 100% rename from iOS/SSZipArchive/minizip/ioapi.h rename to ios/CodePush/SSZipArchive/minizip/ioapi.h diff --git a/iOS/SSZipArchive/minizip/mztools.c b/ios/CodePush/SSZipArchive/minizip/mztools.c similarity index 100% rename from iOS/SSZipArchive/minizip/mztools.c rename to ios/CodePush/SSZipArchive/minizip/mztools.c diff --git a/iOS/SSZipArchive/minizip/mztools.h b/ios/CodePush/SSZipArchive/minizip/mztools.h similarity index 100% rename from iOS/SSZipArchive/minizip/mztools.h rename to ios/CodePush/SSZipArchive/minizip/mztools.h diff --git a/iOS/SSZipArchive/minizip/unzip.c b/ios/CodePush/SSZipArchive/minizip/unzip.c similarity index 100% rename from iOS/SSZipArchive/minizip/unzip.c rename to ios/CodePush/SSZipArchive/minizip/unzip.c diff --git a/iOS/SSZipArchive/minizip/unzip.h b/ios/CodePush/SSZipArchive/minizip/unzip.h similarity index 100% rename from iOS/SSZipArchive/minizip/unzip.h rename to ios/CodePush/SSZipArchive/minizip/unzip.h diff --git a/iOS/SSZipArchive/minizip/zip.c b/ios/CodePush/SSZipArchive/minizip/zip.c similarity index 100% rename from iOS/SSZipArchive/minizip/zip.c rename to ios/CodePush/SSZipArchive/minizip/zip.c diff --git a/iOS/SSZipArchive/minizip/zip.h b/ios/CodePush/SSZipArchive/minizip/zip.h similarity index 100% rename from iOS/SSZipArchive/minizip/zip.h rename to ios/CodePush/SSZipArchive/minizip/zip.h From 1d45e99fd197ca52c631af594a3b34196b2ae123 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 18 Feb 2016 23:51:20 -0800 Subject: [PATCH 6/7] package->update android --- .../codepush/react/CodePushPackage.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java index 9179813..6623caf 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java @@ -153,13 +153,13 @@ public class CodePushPackage { public void downloadPackage(Context applicationContext, ReadableMap updatePackage, DownloadProgressCallback progressCallback) throws IOException { - String newPackageHash = CodePushUtils.tryGetString(updatePackage, PACKAGE_HASH_KEY); - String newPackageFolderPath = getPackageFolderPath(newPackageHash); - String newPackageMetadataPath = CodePushUtils.appendPathComponent(newPackageFolderPath, PACKAGE_FILE_NAME); - if (FileUtils.fileAtPathExists(newPackageFolderPath)) { + String newUpdateHash = CodePushUtils.tryGetString(updatePackage, PACKAGE_HASH_KEY); + String newUpdateFolderPath = getPackageFolderPath(newUpdateHash); + String newUpdateMetadataPath = CodePushUtils.appendPathComponent(newUpdateFolderPath, PACKAGE_FILE_NAME); + if (FileUtils.fileAtPathExists(newUpdateFolderPath)) { // This removes any stale data in newPackageFolderPath that could have been left // uncleared due to a crash or error during the download or install process. - FileUtils.deleteDirectoryAtPath(newPackageFolderPath); + FileUtils.deleteDirectoryAtPath(newUpdateFolderPath); } String downloadUrlString = CodePushUtils.tryGetString(updatePackage, DOWNLOAD_URL_KEY); @@ -232,27 +232,27 @@ public class CodePushPackage { DIFF_MANIFEST_FILE_NAME); if (FileUtils.fileAtPathExists(diffManifestFilePath)) { String currentPackageFolderPath = getCurrentPackageFolderPath(); - CodePushUpdateUtils.copyNecessaryFilesFromCurrentPackage(diffManifestFilePath, currentPackageFolderPath, newPackageFolderPath); + CodePushUpdateUtils.copyNecessaryFilesFromCurrentPackage(diffManifestFilePath, currentPackageFolderPath, newUpdateFolderPath); File diffManifestFile = new File(diffManifestFilePath); diffManifestFile.delete(); } - FileUtils.copyDirectoryContents(unzippedFolderPath, newPackageFolderPath); + FileUtils.copyDirectoryContents(unzippedFolderPath, newUpdateFolderPath); FileUtils.deleteFileAtPathSilently(unzippedFolderPath); // For zip updates, we need to find the relative path to the jsBundle and save it in the // metadata so that we can find and run it easily the next time. - String relativeBundlePath = CodePushUpdateUtils.findJSBundleInUpdateContents(newPackageFolderPath); + String relativeBundlePath = CodePushUpdateUtils.findJSBundleInUpdateContents(newUpdateFolderPath); if (relativeBundlePath == null) { throw new CodePushInvalidUpdateException("Update is invalid - no files with extension .bundle, .js or .jsbundle were found in the update package."); } else { - if (FileUtils.fileAtPathExists(newPackageMetadataPath)) { - File metadataFileFromOldUpdate = new File(newPackageMetadataPath); + if (FileUtils.fileAtPathExists(newUpdateMetadataPath)) { + File metadataFileFromOldUpdate = new File(newUpdateMetadataPath); metadataFileFromOldUpdate.delete(); } - CodePushUpdateUtils.verifyHashForZipUpdate(newPackageFolderPath, newPackageHash); + CodePushUpdateUtils.verifyHashForZipUpdate(newUpdateFolderPath, newUpdateHash); JSONObject updatePackageJSON = CodePushUtils.convertReadableToJsonObject(updatePackage); try { @@ -267,11 +267,11 @@ public class CodePushPackage { } } else { // File is a jsbundle, move it to a folder with the packageHash as its name - FileUtils.moveFile(downloadFile, newPackageFolderPath, UPDATE_BUNDLE_FILE_NAME); + FileUtils.moveFile(downloadFile, newUpdateFolderPath, UPDATE_BUNDLE_FILE_NAME); } // Save metadata to the folder. - CodePushUtils.writeReadableMapToFile(updatePackage, newPackageMetadataPath); + CodePushUtils.writeReadableMapToFile(updatePackage, newUpdateMetadataPath); } public void installPackage(ReadableMap updatePackage, boolean removePendingUpdate) throws IOException { From e8307d6501bdabba8f07030e4ed606e7c8a8d09e Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Fri, 19 Feb 2016 10:58:04 -0800 Subject: [PATCH 7/7] verifyHashForZipUpdate -> verifyHashForDiffUpdate --- .../com/microsoft/codepush/react/CodePushPackage.java | 7 +++++-- .../microsoft/codepush/react/CodePushUpdateUtils.java | 3 +-- ios/CodePush/CodePush.h | 6 +++--- ios/CodePush/CodePushPackage.m | 9 +++++---- ios/CodePush/CodePushUpdateUtils.m | 6 +++--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java index 6623caf..60a9569 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushPackage.java @@ -230,7 +230,8 @@ public class CodePushPackage { // Merge contents with current update based on the manifest String diffManifestFilePath = CodePushUtils.appendPathComponent(unzippedFolderPath, DIFF_MANIFEST_FILE_NAME); - if (FileUtils.fileAtPathExists(diffManifestFilePath)) { + boolean isDiffUpdate = FileUtils.fileAtPathExists(diffManifestFilePath); + if (isDiffUpdate) { String currentPackageFolderPath = getCurrentPackageFolderPath(); CodePushUpdateUtils.copyNecessaryFilesFromCurrentPackage(diffManifestFilePath, currentPackageFolderPath, newUpdateFolderPath); File diffManifestFile = new File(diffManifestFilePath); @@ -252,7 +253,9 @@ public class CodePushPackage { metadataFileFromOldUpdate.delete(); } - CodePushUpdateUtils.verifyHashForZipUpdate(newUpdateFolderPath, newUpdateHash); + if (isDiffUpdate) { + CodePushUpdateUtils.verifyHashForDiffUpdate(newUpdateFolderPath, newUpdateHash); + } JSONObject updatePackageJSON = CodePushUtils.convertReadableToJsonObject(updatePackage); try { diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java index fc97fa6..d8c38ff 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java @@ -31,7 +31,6 @@ public class CodePushUpdateUtils { addContentsOfFolderToManifest(fullFilePath, relativePath, manifest); } else { try { - // Substring 1 because appendPathComponent creates a "/" prefix to the relativePath. manifest.add(relativePath + ":" + computeHash(new FileInputStream(file))); } catch (FileNotFoundException e) { // Should not happen. @@ -103,7 +102,7 @@ public class CodePushUpdateUtils { return null; } - public static void verifyHashForZipUpdate(String folderPath, String expectedHash) { + public static void verifyHashForDiffUpdate(String folderPath, String expectedHash) { ArrayList updateContentsManifest = new ArrayList(); addContentsOfFolderToManifest(folderPath, "", updateContentsManifest); Collections.sort(updateContentsManifest); diff --git a/ios/CodePush/CodePush.h b/ios/CodePush/CodePush.h index b77a531..5584325 100644 --- a/ios/CodePush/CodePush.h +++ b/ios/CodePush/CodePush.h @@ -111,9 +111,9 @@ failCallback:(void (^)(NSError *err))failCallback; error:(NSError **)error; + (NSString *)findMainBundleInFolder:(NSString *)folderPath error:(NSError **)error; -+ (BOOL)verifyHashForZipUpdate:(NSString *)finalUpdateFolder - expectedHash:(NSString *)expectedHash - error:(NSError **)error; ++ (BOOL)verifyHashForDiffUpdate:(NSString *)finalUpdateFolder + expectedHash:(NSString *)expectedHash + error:(NSError **)error; @end diff --git a/ios/CodePush/CodePushPackage.m b/ios/CodePush/CodePushPackage.m index 929f3d3..d5f4d4f 100644 --- a/ios/CodePush/CodePushPackage.m +++ b/ios/CodePush/CodePushPackage.m @@ -257,8 +257,9 @@ NSString * const UnzippedFolderName = @"unzipped"; } NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName]; + BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]) { + if (isDiffUpdate) { // Copy the current package to the new package. NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error]; if (error) { @@ -368,9 +369,9 @@ NSString * const UnzippedFolderName = @"unzipped"; } } - if (![CodePushUpdateUtils verifyHashForZipUpdate:newUpdateFolderPath - expectedHash:newUpdateHash - error:&error]) { + if (isDiffUpdate && ![CodePushUpdateUtils verifyHashForDiffUpdate:newUpdateFolderPath + expectedHash:newUpdateHash + error:&error]) { if (error) { failCallback(error); return; diff --git a/ios/CodePush/CodePushUpdateUtils.m b/ios/CodePush/CodePushUpdateUtils.m index 8a2e23d..d48e95d 100644 --- a/ios/CodePush/CodePushUpdateUtils.m +++ b/ios/CodePush/CodePushUpdateUtils.m @@ -127,9 +127,9 @@ return nil; } -+ (BOOL)verifyHashForZipUpdate:(NSString *)finalUpdateFolder - expectedHash:(NSString *)expectedHash - error:(NSError **)error ++ (BOOL)verifyHashForDiffUpdate:(NSString *)finalUpdateFolder + expectedHash:(NSString *)expectedHash + error:(NSError **)error { NSMutableArray *updateContentsManifest = [NSMutableArray array]; [self addContentsOfFolderToManifest:finalUpdateFolder