diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h --- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h +++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h @@ -10,6 +10,7 @@ const static std::string notificationsCryptoAccountID; const static std::string keyserverHostedNotificationsID; const static std::string initialEncryptedMessageContent; + const static int olmEncryptedTypeMessage; static void serializeAndFlushCryptoModule( crypto::CryptoModule &cryptoModule, diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp --- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp +++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp @@ -23,6 +23,7 @@ "keyserverHostedNotificationsID"; const std::string NotificationsCryptoModule::initialEncryptedMessageContent = "{\"type\": \"init\"}"; +const NotificationsCryptoModule::olmEncryptedTypeMessage = 1; crypto::CryptoModule NotificationsCryptoModule::deserializeCryptoModule( const std::string &path, diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ CB38B48628771CDD00171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; }; CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; }; CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */; }; + CB3C0A3B2A125C8F009BD4DA /* NotificationsCryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */; }; CB3C621127CE4A320054F24C /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; }; CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; }; @@ -1028,6 +1029,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CB3C0A3B2A125C8F009BD4DA /* NotificationsCryptoModule.cpp in Sources */, CB90951F29534B32002F2A7F /* CommSecureStore.mm in Sources */, CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */, CB38B48528771CB800171182 /* EncryptedFileUtils.mm in Sources */, diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm --- a/native/ios/NotificationService/NotificationService.mm +++ b/native/ios/NotificationService/NotificationService.mm @@ -1,8 +1,11 @@ #import "NotificationService.h" #import "Logger.h" +#import "NotificationsCryptoModule.h" #import "TemporaryMessageStorage.h" NSString *const backgroundNotificationTypeKey = @"backgroundNotifType"; +NSString *const messageInfosKey = @"messageInfos"; +const std::string callingProcessName = "NSE"; // The context for this constant can be found here: // https://linear.app/comm/issue/ENG-3074#comment-bd2f5e28 int64_t const notificationRemovalDelay = (int64_t)(0.1 * NSEC_PER_SEC); @@ -26,6 +29,10 @@ self.contentHandler = contentHandler; self.bestAttemptContent = [request.content mutableCopy]; + if ([self shouldBeDecrypted:self.bestAttemptContent.userInfo]) { + [self decryptBestAttemptContent]; + } + [self persistMessagePayload:self.bestAttemptContent.userInfo]; // Message payload persistence is a higher priority task, so it has // to happen prior to potential notification center clearing. @@ -52,6 +59,16 @@ // It is an extremely unlikely to happen. comm::Logger::log("NSE: Exceeded time limit to rescind a notification."); self.contentHandler([[UNNotificationContent alloc] init]); + return; + } + if ([self shouldBeDecrypted:self.bestAttemptContent.userInfo] && + !self.bestAttemptContent.userInfo[@"succesfullyDecrypted"]) { + // If we get to this place it means we were unable to + // decrypt encrypted notification content in time + // given to NSE to process notification. + comm::Logger::log("NSE: Exceeded time limit to decrypt a notification."); + self.contentHandler([[UNNotificationContent alloc] init]); + return; } self.contentHandler(self.bestAttemptContent); } @@ -85,10 +102,10 @@ } - (void)persistMessagePayload:(NSDictionary *)payload { - if (payload[@"messageInfos"]) { + if (payload[messageInfosKey]) { TemporaryMessageStorage *temporaryStorage = [[TemporaryMessageStorage alloc] init]; - [temporaryStorage writeMessage:payload[@"messageInfos"]]; + [temporaryStorage writeMessage:payload[messageInfosKey]]; return; } @@ -131,4 +148,58 @@ TRUE); } +- (BOOL)shouldBeDecrypted:(NSDictionary *)payload { + return payload[@"encrypted"] && + [payload[@"encrypted"] isEqualToString:@"true"]; +} + +- (void)decryptBestAttemptContent { + std::string encryptedBody = + std::string([self.bestAttemptContent.body UTF8String]); + NSString *decryptedBody = + [NSString stringWithUTF8String:(comm::NotificationsCryptoModule::decrypt( + encryptedBody, 1, callingProcessName)) + .c_str()]; + self.bestAttemptContent.body = decryptedBody; + + std::string encryptedThreadID = + std::string([self.bestAttemptContent.threadIdentifier UTF8String]); + NSString *decryptedThreadID = [NSString + stringWithUTF8String: + (comm::NotificationsCryptoModule::decrypt( + encryptedThreadID, + comm::NotificationsCryptoModule::olmEncryptedTypeMessage, + "NSE")) + .c_str()]; + self.bestAttemptContent.threadIdentifier = decryptedThreadID; + + std::string encryptedBadge = + std::string([self.bestAttemptContent.userInfo[@"badge"] UTF8String]); + NSNumber *decryptedBadge = @([[NSString + stringWithUTF8String: + (comm::NotificationsCryptoModule::decrypt( + encryptedBadge, + comm::NotificationsCryptoModule::olmEncryptedTypeMessage, + callingProcessName)) + .c_str()] intValue]); + self.bestAttemptContent.badge = decryptedBadge; + + NSMutableDictionary *mutableUserInfo = + [self.bestAttemptContent.userInfo mutableCopy]; + + std::string encryptedMessageInfos = + std::string([mutableUserInfo[messageInfosKey] UTF8String]); + NSString *decryptedMessageInfos = [NSString + stringWithUTF8String: + (comm::NotificationsCryptoModule::decrypt( + encryptedMessageInfos, + comm::NotificationsCryptoModule::olmEncryptedTypeMessage, + callingProcessName)) + .c_str()]; + mutableUserInfo[messageInfosKey] = decryptedMessageInfos; + + mutableUserInfo[@"succesfullyDecrypted"] = @(YES); + self.bestAttemptContent.userInfo = mutableUserInfo; +} + @end