diff --git a/Podfile b/Podfile index 165a6af81773..d4498c47f16c 100644 --- a/Podfile +++ b/Podfile @@ -38,9 +38,9 @@ end def wordpress_kit - pod 'WordPressKit', '~> 4.18.0-beta' + #pod 'WordPressKit', '~> 4.18.0-beta' #pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :tag => '' - #pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :branch => '' + pod 'WordPressKit', :git => 'https://github.com/Deco354/WordPressKit-iOS.git', :branch => 'feature/remote-content-hash' #pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :commit => '' #pod 'WordPressKit', :path => '../WordPressKit-iOS' end diff --git a/Podfile.lock b/Podfile.lock index 79220740b7c4..c128fdc54adf 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -407,7 +407,7 @@ PODS: - WordPressKit (~> 4.18-beta) - WordPressShared (~> 1.12-beta) - WordPressUI (~> 1.7.0) - - WordPressKit (4.18.0): + - WordPressKit (4.19-beta.3): - Alamofire (~> 4.8.0) - CocoaLumberjack (~> 3.4) - NSObject-SafeExpectations (= 0.0.4) @@ -506,7 +506,7 @@ DEPENDENCIES: - SVProgressHUD (= 2.2.5) - WordPress-Editor-iOS (~> 1.19.3) - WordPressAuthenticator (~> 1.26.0-beta) - - WordPressKit (~> 4.18.0-beta) + - WordPressKit (from `https://github.com/Deco354/WordPressKit-iOS.git`, branch `feature/remote-content-hash`) - WordPressMocks (~> 0.0.8) - WordPressShared (~> 1.12.0) - WordPressUI (~> 1.7.1) @@ -556,7 +556,6 @@ SPEC REPOS: - WordPress-Aztec-iOS - WordPress-Editor-iOS - WordPressAuthenticator - - WordPressKit - WordPressMocks - WordPressShared - WordPressUI @@ -657,6 +656,9 @@ EXTERNAL SOURCES: :commit: 5ff93360313e9919c7a4b7f0faa1cb9e5e9c3542 :git: http://github.com/wordpress-mobile/gutenberg-mobile/ :submodules: true + WordPressKit: + :branch: feature/remote-content-hash + :git: https://github.com/Deco354/WordPressKit-iOS.git Yoga: :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/5ff93360313e9919c7a4b7f0faa1cb9e5e9c3542/third-party-podspecs/Yoga.podspec.json @@ -675,6 +677,9 @@ CHECKOUT OPTIONS: :commit: 5ff93360313e9919c7a4b7f0faa1cb9e5e9c3542 :git: http://github.com/wordpress-mobile/gutenberg-mobile/ :submodules: true + WordPressKit: + :commit: 7dc25bbdbdd22dfe2772ac38da2c058087ce5f9b + :git: https://github.com/Deco354/WordPressKit-iOS.git SPEC CHECKSUMS: 1PasswordExtension: f97cc80ae58053c331b2b6dc8843ba7103b33794 @@ -756,7 +761,7 @@ SPEC CHECKSUMS: WordPress-Aztec-iOS: b7ac8b30f746992e85d9668453ac87c2cdcecf4f WordPress-Editor-iOS: 1886f7fe464d79ee64ccfe7985281f8cf45f75eb WordPressAuthenticator: 31bceb4ab25de663a327b791e76a405b9c903b73 - WordPressKit: 1d10fa14ea185600472d31cf25e677c7d938b17d + WordPressKit: 8a7cf458497a593cf8b1bfa6c965dcfd5d072ec0 WordPressMocks: b4064b99a073117bbc304abe82df78f2fbe60992 WordPressShared: 38cb62e9cb998d4dc3c1611f17934c6875a6b3e8 WordPressUI: 9da5d966b8beb091950cd96880db398d7f30e246 @@ -772,6 +777,6 @@ SPEC CHECKSUMS: ZendeskSupportSDK: a87ab1e4badace92c75eb11dc77ede1e995b2adc ZIPFoundation: 249fa8890597086cd536bb2df5c9804d84e122b0 -PODFILE CHECKSUM: 6141b62876d49dbc9b2e5735cff154f0244a888f +PODFILE CHECKSUM: 267bf560442ff5d1b7cadc184cd0a691b3eb5c10 COCOAPODS: 1.9.3 diff --git a/WordPress/Classes/Models/AbstractPost+HashHelpers.m b/WordPress/Classes/Models/AbstractPost+HashHelpers.m index 4c573886cbdd..7edeaaea66a5 100644 --- a/WordPress/Classes/Models/AbstractPost+HashHelpers.m +++ b/WordPress/Classes/Models/AbstractPost+HashHelpers.m @@ -1,6 +1,7 @@ #import "AbstractPost+HashHelpers.h" #import "Media+WPMediaAsset.h" #import "WordPress-Swift.h" +@import WordPressKit; @implementation AbstractPost (HashHelpers) @@ -10,25 +11,23 @@ - (NSString *)calculateConfirmedChangesContentHash { // that's the purpose of the `-additionalContentHashes` extension point. NSArray *hashedContents = @[ - [self hashForNSInteger:self.blog.dotComID.integerValue], - [self hashForNSInteger:self.postID.integerValue], - [self hashForString:self.postTitle], - [self hashForString:self.content], - [self hashForDouble:self.dateCreated.timeIntervalSinceReferenceDate], - [self hashForString:self.permaLink], - [self hashForString:self.mt_excerpt], - [self hashForString:self.status], - [self hashForString:self.password], - [self hashForString:self.author], - [self hashForNSInteger:self.authorID.integerValue], - [self hashForString:self.featuredImage.identifier], - [self hashForString:self.wp_slug]]; + [SHAHasher hashForNSInteger:self.blog.dotComID.integerValue], + [SHAHasher hashForNSInteger:self.postID.integerValue], + [SHAHasher hashForString:self.postTitle], + [SHAHasher hashForString:self.content], + [SHAHasher hashForDouble:self.dateCreated.timeIntervalSinceReferenceDate], + [SHAHasher hashForString:self.permaLink], + [SHAHasher hashForString:self.mt_excerpt], + [SHAHasher hashForString:self.status], + [SHAHasher hashForString:self.password], + [SHAHasher hashForString:self.author], + [SHAHasher hashForNSInteger:self.authorID.integerValue], + [SHAHasher hashForString:self.featuredImage.identifier], + [SHAHasher hashForString:self.wp_slug]]; NSArray *finalHashes = [hashedContents arrayByAddingObjectsFromArray:self.additionalContentHashes]; - NSMutableData *mutableData = [NSMutableData data]; - // So, there are multiple ways of combining all those hashes. You need to be careful not to lose the entropy though. // Initially, I wanted to just XOR them together, which is totally reasonable thing to do! // ...however, things get tricky when you XOR things that might be similar/the same. @@ -42,64 +41,11 @@ - (NSString *)calculateConfirmedChangesContentHash { // What I'm doing here instead is just treating all the "partial" hashes as a dumb bag of bits, // combining them together and the final hash is SHA256 of _that_. // Hopefully that'll be enough. - - for (NSData *hash in finalHashes) { - [mutableData appendData:hash]; - } - - unsigned char finalDigest[CC_SHA256_DIGEST_LENGTH]; - - CC_SHA256(mutableData.bytes, (CC_LONG)mutableData.length, finalDigest); - - return [self sha256StringFromData:[NSData dataWithBytes:finalDigest length:CC_SHA256_DIGEST_LENGTH]]; + return [SHAHasher combineHashes:finalHashes]; } - - (NSArray *)additionalContentHashes { return @[]; } -#pragma mark - SHA256 calculations - -- (NSData *)hashForString:(NSString *) string { - if (!string) { - return [[NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH] copy]; - } - - NSData *encodedBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; - unsigned char digest[CC_SHA256_DIGEST_LENGTH]; - - CC_SHA256(encodedBytes.bytes, (CC_LONG)encodedBytes.length, digest); - - return [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; -} - -- (NSData *)hashForNSInteger:(NSInteger)integer { - unsigned char digest[CC_SHA256_DIGEST_LENGTH]; - - CC_SHA256(&integer, sizeof(integer), digest); - - return [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; -} - -- (NSData *)hashForDouble:(double)dbl { - unsigned char digest[CC_SHA256_DIGEST_LENGTH]; - - CC_SHA256(&dbl, sizeof(dbl), digest); - - return [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; -} - -- (NSString *)sha256StringFromData:(NSData *)data { - NSMutableString *mutableString = [NSMutableString string]; - - const char *hashBytes = [data bytes]; - - for (int i = 0; i < data.length; i++) { - [mutableString appendFormat:@"%02.2hhx", hashBytes[i]]; - } - - return [mutableString copy]; -} - @end diff --git a/WordPress/Classes/Models/AbstractPost.h b/WordPress/Classes/Models/AbstractPost.h index 243a0ead2343..d0aa420fb0aa 100644 --- a/WordPress/Classes/Models/AbstractPost.h +++ b/WordPress/Classes/Models/AbstractPost.h @@ -59,6 +59,7 @@ typedef NS_ENUM(NSUInteger, AbstractPostRemoteStatus) { @property (nonatomic, copy, nullable) NSNumber *autosaveIdentifier; @property (nonatomic) BOOL hasVersionConflict; +@property (nonatomic, copy, nullable) NSString *lastRemoteUpdateHash; // Revision management - (AbstractPost *)createRevision; diff --git a/WordPress/Classes/Models/AbstractPost.m b/WordPress/Classes/Models/AbstractPost.m index 212f27d48688..ba355b286d31 100644 --- a/WordPress/Classes/Models/AbstractPost.m +++ b/WordPress/Classes/Models/AbstractPost.m @@ -39,6 +39,7 @@ @implementation AbstractPost @dynamic autosaveModifiedDate; @dynamic autosaveIdentifier; @dynamic hasVersionConflict; +@dynamic lastRemoteUpdateHash; @synthesize restorableStatus; diff --git a/WordPress/Classes/Models/Post.swift b/WordPress/Classes/Models/Post.swift index 9a45f6182172..03783586173c 100644 --- a/WordPress/Classes/Models/Post.swift +++ b/WordPress/Classes/Models/Post.swift @@ -318,12 +318,12 @@ class Post: AbstractPost { return acc + obj } ?? "" - return [hash(for: publicID ?? ""), - hash(for: tags ?? ""), - hash(for: postFormat ?? ""), - hash(for: stringifiedCategories), - hash(for: geolocation?.latitude ?? 0), - hash(for: geolocation?.longitude ?? 0), - hash(for: isStickyPost ? 1 : 0)] + return [SHAHasher.hash(for: publicID ?? ""), + SHAHasher.hash(for: tags ?? ""), + SHAHasher.hash(for: postFormat ?? ""), + SHAHasher.hash(for: stringifiedCategories), + SHAHasher.hash(for: geolocation?.latitude ?? 0), + SHAHasher.hash(for: geolocation?.longitude ?? 0), + SHAHasher.hash(for: isStickyPost ? 1 : 0)] } } diff --git a/WordPress/Classes/Services/PostService.m b/WordPress/Classes/Services/PostService.m index 50e48a4fce2b..7b69491a576d 100644 --- a/WordPress/Classes/Services/PostService.m +++ b/WordPress/Classes/Services/PostService.m @@ -775,21 +775,22 @@ - (NSDictionary *)remoteSyncParametersDictionaryForRemote:(nonnull id _XCCurrentVersionName - WordPress 100.xcdatamodel + WordPress 101.xcdatamodel diff --git a/WordPress/Classes/WordPress.xcdatamodeld/WordPress 101.xcdatamodel/contents b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 101.xcdatamodel/contents new file mode 100644 index 000000000000..eb05327bf66d --- /dev/null +++ b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 101.xcdatamodel/contents @@ -0,0 +1,963 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 7b35c39cfc56..e572557e5f07 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2593,6 +2593,7 @@ 10BBFF34EBDA2F9B8CB48DF6 /* Pods-WordPressUITests.release-internal.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressUITests.release-internal.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressUITests/Pods-WordPressUITests.release-internal.xcconfig"; sourceTree = ""; }; 131D0EE49695795ECEDAA446 /* Pods-WordPressTest.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressTest.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressTest/Pods-WordPressTest.release-alpha.xcconfig"; sourceTree = ""; }; 1431237D252D048D005B08B7 /* WordPress 100.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 100.xcdatamodel"; sourceTree = ""; }; + 1495C6A22539EB1D00421E22 /* WordPress 101.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 101.xcdatamodel"; sourceTree = ""; }; 1702BBDB1CEDEA6B00766A33 /* BadgeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BadgeLabel.swift; sourceTree = ""; }; 1702BBDF1CF3034E00766A33 /* DomainsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainsService.swift; sourceTree = ""; }; 1703D04B20ECD93800D292E9 /* Routes+Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Routes+Post.swift"; sourceTree = ""; }; @@ -17281,6 +17282,7 @@ E125443B12BF5A7200D87A0A /* WordPress.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 1495C6A22539EB1D00421E22 /* WordPress 101.xcdatamodel */, 1431237D252D048D005B08B7 /* WordPress 100.xcdatamodel */, 46183CF1251BD5F1004F9AFD /* WordPress 99.xcdatamodel */, 8BD8201724BC93B500FF25FD /* WordPress 98.xcdatamodel */, @@ -17382,7 +17384,7 @@ 8350E15911D28B4A00A7B073 /* WordPress.xcdatamodel */, E125443D12BF5A7200D87A0A /* WordPress 2.xcdatamodel */, ); - currentVersion = 1431237D252D048D005B08B7 /* WordPress 100.xcdatamodel */; + currentVersion = 1495C6A22539EB1D00421E22 /* WordPress 101.xcdatamodel */; name = WordPress.xcdatamodeld; path = Classes/WordPress.xcdatamodeld; sourceTree = ""; diff --git a/WordPress/WordPressTest/PostTests.swift b/WordPress/WordPressTest/PostTests.swift index cf8e6c7f1688..073e3dbe8d24 100644 --- a/WordPress/WordPressTest/PostTests.swift +++ b/WordPress/WordPressTest/PostTests.swift @@ -425,6 +425,29 @@ class PostTests: XCTestCase { XCTAssertNotEqual(post.calculateConfirmedChangesContentHash(), correctHash) } + func testAdditionalContentHashing() { + let post = newTestPost() + let hashWithoutAdditionalContent = post.additionalContentHashes() + + addAdditionalContent(to: post) + XCTAssertNotEqual(hashWithoutAdditionalContent, post.additionalContentHashes()) + XCTAssertEqual(post.additionalContentHashes(), post.additionalContentHashes()) + } + + func testAdditionalContentHashingImpactsMainHash() { + let correctHash = "d8edd9c05c941d2c7e697c00fd34b60cdf5e7d572a762fb39fbbee5ef9db177a" + + let post = newTestPost() + let hashWithoutAdditionalContent = post.calculateConfirmedChangesContentHash() + addAdditionalContent(to: post) + XCTAssertNotEqual(post.calculateConfirmedChangesContentHash(), hashWithoutAdditionalContent) + XCTAssertEqual(post.calculateConfirmedChangesContentHash(), correctHash) + } + + private func addAdditionalContent(to post: Post) { + post.addCategories([newTestPostCategory("endgames"), newTestPostCategory("openings")]) + } + func testAutoUploadExpiration() { let post = newTestPost()