Skip to content

Commit 5b1c56d

Browse files
committed
iOS: consolidate SHA-256 hashing into a shared utility
1 parent 8d8890f commit 5b1c56d

3 files changed

Lines changed: 92 additions & 21 deletions

File tree

ios/CodePush/CodePushSha256.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#import <Foundation/Foundation.h>
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
// SHA-256 hex digest of a file's contents.
6+
// Returns nil and sets *error if the file can't be opened/read.
7+
NSString * _Nullable CodePushSha256HexForFile(NSString *filePath, NSError **error);
8+
9+
// SHA-256 hex digest of an in-memory buffer.
10+
NSString *CodePushSha256HexForData(NSData *data);
11+
12+
NS_ASSUME_NONNULL_END

ios/CodePush/CodePushSha256.m

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#import "CodePushSha256.h"
2+
#include <CommonCrypto/CommonDigest.h>
3+
4+
static NSString *const CodePushSha256ErrorDomain = @"CodePushSha256Error";
5+
6+
static NSString *hexStringForDigest(unsigned char digest[CC_SHA256_DIGEST_LENGTH])
7+
{
8+
NSMutableString *hex = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
9+
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
10+
[hex appendFormat:@"%02x", digest[i]];
11+
}
12+
return hex;
13+
}
14+
15+
NSString *CodePushSha256HexForData(NSData *data)
16+
{
17+
unsigned char digest[CC_SHA256_DIGEST_LENGTH];
18+
CC_SHA256(data.bytes, (CC_LONG)data.length, digest);
19+
return hexStringForDigest(digest);
20+
}
21+
22+
NSString *CodePushSha256HexForFile(NSString *filePath, NSError **error)
23+
{
24+
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
25+
if (!fileHandle) {
26+
if (error) {
27+
*error = [NSError errorWithDomain:CodePushSha256ErrorDomain
28+
code:1
29+
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Could not open file for reading: %@", filePath] }];
30+
}
31+
return nil;
32+
}
33+
34+
CC_SHA256_CTX context;
35+
CC_SHA256_Init(&context);
36+
37+
static const NSUInteger kChunkSize = 1024 * 8;
38+
NSError *readError;
39+
while (YES) {
40+
NSData *chunk = [fileHandle readDataUpToLength:kChunkSize error:&readError];
41+
if (readError) {
42+
[fileHandle closeFile];
43+
if (error) {
44+
*error = [NSError errorWithDomain:CodePushSha256ErrorDomain
45+
code:2
46+
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Could not read file: %@", filePath],
47+
NSUnderlyingErrorKey: readError }];
48+
}
49+
return nil;
50+
}
51+
if (chunk.length == 0) {
52+
break;
53+
}
54+
CC_SHA256_Update(&context, chunk.bytes, (CC_LONG)chunk.length);
55+
}
56+
[fileHandle closeFile];
57+
58+
unsigned char digest[CC_SHA256_DIGEST_LENGTH];
59+
CC_SHA256_Final(digest, &context);
60+
return hexStringForDigest(digest);
61+
}

ios/CodePush/CodePushUpdateUtils.m

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#import "CodePush.h"
2-
#include <CommonCrypto/CommonDigest.h>
2+
#import "CodePushSha256.h"
33
#import "JWT.h"
44

55
@implementation CodePushUpdateUtils
@@ -57,23 +57,29 @@ + (BOOL)addContentsOfFolderToManifest:(NSString *)folderPath
5757
return NO;
5858
}
5959
} else {
60-
NSData *fileContents = [NSData dataWithContentsOfFile:fullFilePath];
61-
NSString *fileContentsHash = [self computeHashForData:fileContents];
60+
NSString *fileContentsHash = CodePushSha256HexForFile(fullFilePath, error);
61+
if (!fileContentsHash) {
62+
return NO;
63+
}
6264
[manifest addObject:[[relativePath stringByAppendingString:@":"] stringByAppendingString:fileContentsHash]];
6365
}
6466
}
6567

6668
return YES;
6769
}
6870

69-
+ (void)addFileToManifest:(NSURL *)fileURL
71+
+ (BOOL)addFileToManifest:(NSURL *)fileURL
7072
manifest:(NSMutableArray *)manifest
73+
error:(NSError **)error
7174
{
7275
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
73-
NSData *fileContents = [NSData dataWithContentsOfURL:fileURL];
74-
NSString *fileContentsHash = [self computeHashForData:fileContents];
76+
NSString *fileContentsHash = CodePushSha256HexForFile([fileURL path], error);
77+
if (!fileContentsHash) {
78+
return NO;
79+
}
7580
[manifest addObject:[NSString stringWithFormat:@"%@/%@:%@", [self manifestFolderPrefix], [fileURL lastPathComponent], fileContentsHash]];
7681
}
82+
return YES;
7783
}
7884

7985
+ (NSString *)computeFinalHashFromManifest:(NSMutableArray *)manifest
@@ -93,19 +99,7 @@ + (NSString *)computeFinalHashFromManifest:(NSMutableArray *)manifest
9399
// The JSON serialization turns path separators into "\/", e.g. "CodePush\/assets\/image.png"
94100
manifestString = [manifestString stringByReplacingOccurrencesOfString:@"\\/"
95101
withString:@"/"];
96-
return [self computeHashForData:[NSData dataWithBytes:manifestString.UTF8String length:[manifestString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]];
97-
}
98-
99-
+ (NSString *)computeHashForData:(NSData *)inputData
100-
{
101-
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
102-
CC_SHA256(inputData.bytes, (CC_LONG)inputData.length, digest);
103-
NSMutableString* inputHash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
104-
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
105-
[inputHash appendFormat:@"%02x", digest[i]];
106-
}
107-
108-
return inputHash;
102+
return CodePushSha256HexForData([NSData dataWithBytes:manifestString.UTF8String length:[manifestString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]);
109103
}
110104

111105
+ (BOOL)copyEntriesInFolder:(NSString *)sourceFolder
@@ -230,8 +224,12 @@ + (NSString *)getHashForBinaryContents:(NSURL *)binaryBundleUrl
230224
}
231225
}
232226

233-
[self addFileToManifest:binaryBundleUrl manifest:manifest];
234-
[self addFileToManifest:[binaryBundleUrl URLByAppendingPathExtension:@"meta"] manifest:manifest];
227+
if (![self addFileToManifest:binaryBundleUrl manifest:manifest error:error]) {
228+
return nil;
229+
}
230+
if (![self addFileToManifest:[binaryBundleUrl URLByAppendingPathExtension:@"meta"] manifest:manifest error:error]) {
231+
return nil;
232+
}
235233

236234
binaryHash = [self computeFinalHashFromManifest:manifest error:error];
237235

0 commit comments

Comments
 (0)