MessageProcessor.m 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import <CoreData/CoreData.h>
  21. #import "Threema-Swift.h"
  22. #import "MessageProcessor.h"
  23. #import "MessageDecoder.h"
  24. #import "BoxTextMessage.h"
  25. #import "BoxImageMessage.h"
  26. #import "BoxVideoMessage.h"
  27. #import "BoxLocationMessage.h"
  28. #import "BoxAudioMessage.h"
  29. #import "BoxedMessage.h"
  30. #import "BoxVoIPCallOfferMessage.h"
  31. #import "BoxVoIPCallAnswerMessage.h"
  32. #import "DeliveryReceiptMessage.h"
  33. #import "TypingIndicatorMessage.h"
  34. #import "GroupCreateMessage.h"
  35. #import "GroupLeaveMessage.h"
  36. #import "GroupRenameMessage.h"
  37. #import "GroupTextMessage.h"
  38. #import "GroupLocationMessage.h"
  39. #import "GroupVideoMessage.h"
  40. #import "GroupImageMessage.h"
  41. #import "GroupAudioMessage.h"
  42. #import "GroupSetPhotoMessage.h"
  43. #import "GroupRequestSyncMessage.h"
  44. #import "LocationMessage.h"
  45. #import "TextMessage.h"
  46. #import "ImageMessage.h"
  47. #import "VideoMessage.h"
  48. #import "AudioMessage.h"
  49. #import "BoxFileMessage.h"
  50. #import "GroupFileMessage.h"
  51. #import "ContactSetPhotoMessage.h"
  52. #import "ContactDeletePhotoMessage.h"
  53. #import "ContactRequestPhotoMessage.h"
  54. #import "GroupDeletePhotoMessage.h"
  55. #import "UnknownTypeMessage.h"
  56. #import "Contact.h"
  57. #import "Conversation.h"
  58. #import "ImageData.h"
  59. #import "AppDelegate.h"
  60. #import "Utils.h"
  61. #import "ProtocolDefines.h"
  62. #import "UserSettings.h"
  63. #import "TypingIndicatorManager.h"
  64. #import "MyIdentityStore.h"
  65. #import "NSString+Hex.h"
  66. #import "ImageMessageLoader.h"
  67. #import "AnimGifMessageLoader.h"
  68. #import "ContactGroupPhotoLoader.h"
  69. #import "NaClCrypto.h"
  70. #import "PinnedHTTPSURLLoader.h"
  71. #import "ValidationLogger.h"
  72. #import "BallotMessageDecoder.h"
  73. #import "BlobUtil.h"
  74. #import "GroupProxy.h"
  75. #import "EntityManager.h"
  76. #import "MessageSender.h"
  77. #import "GroupMessageProcessor.h"
  78. #import "ThreemaError.h"
  79. #import "DatabaseManager.h"
  80. #import "FileMessageDecoder.h"
  81. #import "UTIConverter.h"
  82. #import "DocumentManager.h"
  83. #import "VoIPCallMessageDecoder.h"
  84. #import "BoxVoIPCallIceCandidatesMessage.h"
  85. #import "BoxVoIPCallHangupMessage.h"
  86. #import "BoxVoIPCallRingingMessage.h"
  87. #import "NotificationManager.h"
  88. #import "PushSetting.h"
  89. #import "NonceHasher.h"
  90. #import "UIDefines.h"
  91. #import "ServerConnector.h"
  92. #import "AppGroup.h"
  93. #ifdef DEBUG
  94. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  95. #else
  96. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  97. #endif
  98. @interface MessageProcessor () <GroupMessageProcessorDelegate>
  99. @property EntityManager *entityManager;
  100. @property NSMutableOrderedSet *pendingGroupMessages;
  101. @end
  102. @implementation MessageProcessor
  103. + (MessageProcessor*)sharedMessageProcessor {
  104. static MessageProcessor *instance;
  105. @synchronized (self) {
  106. if (!instance) {
  107. instance = [[MessageProcessor alloc] init];
  108. }
  109. }
  110. return instance;
  111. }
  112. - (instancetype)init {
  113. self = [super init];
  114. if (self) {
  115. _pendingGroupMessages = [[NSMutableOrderedSet alloc] init];
  116. _entityManager = [[EntityManager alloc] init];
  117. }
  118. return self;
  119. }
  120. - (void)processIncomingMessage:(BoxedMessage*)boxmsg receivedAfterInitialQueueSend:(BOOL)receivedAfterInitialQueueSend onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  121. /* blacklisted? */
  122. if ([[UserSettings sharedUserSettings].blacklist containsObject:boxmsg.fromIdentity]) {
  123. DDLogWarn(@"Ignoring message from blocked ID %@", boxmsg.fromIdentity);
  124. onError([ThreemaError threemaError:@"Message received from blocked contact" withCode:kBlockUnknownContactErrorCode]);
  125. return;
  126. }
  127. dispatch_async(dispatch_get_main_queue(), ^{
  128. [[ValidationLogger sharedValidationLogger] logString:@"Threema Web: processIncomingMessage --> connect all running sessions"];
  129. [[WCSessionManager shared] connectAllRunningSessions];
  130. [MessageDecoder decodeFromBoxed:boxmsg isIncomming:YES onCompletion:^(AbstractMessage *amsg) {
  131. if (amsg == nil) {
  132. onError([ThreemaError threemaError:@"Bad message format or decryption error" withCode:kBadMessageErrorCode]);
  133. return;
  134. }
  135. if ([amsg isKindOfClass: [UnknownTypeMessage class]]) {
  136. onError([ThreemaError threemaError:@"Unknown message type" withCode:kUnknownMessageTypeErrorCode]);
  137. return;
  138. }
  139. // Validation logging
  140. if ([amsg isContentValid] == NO) {
  141. if ([amsg isKindOfClass:[BoxTextMessage class]] || [amsg isKindOfClass:[GroupTextMessage class]]) {
  142. [[ValidationLogger sharedValidationLogger] logBoxedMessage:boxmsg isIncoming:YES description:@"Ignore invalid content"];
  143. } else {
  144. [[ValidationLogger sharedValidationLogger] logSimpleMessage:amsg isIncoming:YES description:@"Ignore invalid content"];
  145. }
  146. } else {
  147. if ([_entityManager.entityFetcher isMessageAlreadyInDb:amsg]) {
  148. if ([amsg isKindOfClass:[BoxTextMessage class]] || [amsg isKindOfClass:[GroupTextMessage class]]) {
  149. [[ValidationLogger sharedValidationLogger] logBoxedMessage:boxmsg isIncoming:YES description:@"Message already in database"];
  150. } else {
  151. [[ValidationLogger sharedValidationLogger] logSimpleMessage:amsg isIncoming:YES description:@"Message already in database"];
  152. }
  153. } else {
  154. if ([_entityManager.entityFetcher isNonceAlreadyInDb:amsg]) {
  155. if ([amsg isKindOfClass:[BoxTextMessage class]] || [amsg isKindOfClass:[GroupTextMessage class]]) {
  156. [[ValidationLogger sharedValidationLogger] logBoxedMessage:boxmsg isIncoming:YES description:@"Nonce already in database"];
  157. } else {
  158. [[ValidationLogger sharedValidationLogger] logSimpleMessage:amsg isIncoming:YES description:@"Nonce already in database"];
  159. }
  160. } else {
  161. if ([amsg isKindOfClass:[BoxTextMessage class]] || [amsg isKindOfClass:[GroupTextMessage class]]) {
  162. [[ValidationLogger sharedValidationLogger] logBoxedMessage:boxmsg isIncoming:YES description:nil];
  163. } else {
  164. [[ValidationLogger sharedValidationLogger] logSimpleMessage:amsg isIncoming:YES description:nil];
  165. }
  166. }
  167. }
  168. }
  169. amsg.receivedAfterInitialQueueSend = receivedAfterInitialQueueSend;
  170. [self processIncomingAbstractMessage:amsg onCompletion:onCompletion onError:onError];
  171. } onError:^(NSError *err) {
  172. onError(err);
  173. }];
  174. });
  175. }
  176. - (void)processIncomingAbstractMessage:(AbstractMessage*)amsg onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  177. if ([amsg isContentValid] == NO) {
  178. DDLogInfo(@"Ignore invalid content, message ID %@ from %@", amsg.messageId, amsg.fromIdentity);
  179. onCompletion();
  180. return;
  181. }
  182. if ([_entityManager.entityFetcher isMessageAlreadyInDb:amsg]) {
  183. DDLogInfo(@"Message ID %@ from %@ already in database", amsg.messageId, amsg.fromIdentity);
  184. onCompletion();
  185. return;
  186. }
  187. if ([_entityManager.entityFetcher isNonceAlreadyInDb:amsg]) {
  188. DDLogInfo(@"Message nonce from %@ already in database", amsg.fromIdentity);
  189. onCompletion();
  190. return;
  191. }
  192. /* Find contact for message */
  193. Contact *contact = [_entityManager.entityFetcher contactForId: amsg.fromIdentity];
  194. if (contact == nil) {
  195. /* This should never happen, as without an entry in the contacts database, we wouldn't have
  196. been able to decrypt this message in the first place (no sender public key) */
  197. DDLogWarn(@"Identity %@ not in local contacts database - cannot process message", amsg.fromIdentity);
  198. NSError *error = [ThreemaError threemaError:[NSString stringWithFormat:@"Identity %@ not in local contacts database - cannot process message", amsg.fromIdentity]];
  199. onError(error);
  200. return;
  201. }
  202. /* Update public nickname in contact, if necessary */
  203. if (![amsg isKindOfClass:[DeliveryReceiptMessage class]] && (contact.publicNickname == nil || ![contact.publicNickname isEqualToString:amsg.pushFromName])) {
  204. contact.publicNickname = amsg.pushFromName;
  205. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationRefreshContactSortIndices object:nil];
  206. }
  207. DDLogVerbose(@"processIncomingMessage: %@", amsg);
  208. [[PendingMessagesManager shared] pendingMessageWithSenderId:nil messageId:nil abstractMessage:amsg threemaDict:nil completion:^(PendingMessage *pendingMessage) {
  209. @try {
  210. pendingMessage.isPendingGroupMessages = false;
  211. if ([amsg isKindOfClass:[AbstractGroupMessage class]]) {
  212. [self processIncomingGroupMessage:(AbstractGroupMessage *)amsg pendingMessage:pendingMessage onCompletion:^{
  213. [_entityManager performSyncBlockAndSafe:^{
  214. [_entityManager.entityCreator nonceWithData:[NonceHasher hashedNonce:amsg.nonce]];
  215. }];
  216. onCompletion();
  217. } onError:onError];
  218. } else {
  219. [self processIncomingMessage:(AbstractMessage *)amsg pendingMessage:pendingMessage onCompletion:^{
  220. if (!amsg.immediate) {
  221. [_entityManager performSyncBlockAndSafe:^{
  222. [_entityManager.entityCreator nonceWithData:[NonceHasher hashedNonce:amsg.nonce]];
  223. }];
  224. }
  225. onCompletion();
  226. } onError:onError];
  227. }
  228. } @catch (NSException *exception) {
  229. NSError *error = [ThreemaError threemaError:exception.description withCode:kMessageProcessingErrorCode];
  230. onError(error);
  231. } @catch (NSError *error) {
  232. onError(error);
  233. }
  234. }];
  235. }
  236. - (void)processIncomingMessage:(AbstractMessage*)amsg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  237. Conversation *conversation = [self preprocessStorableMessage:amsg];
  238. if ([amsg needsConversation] && conversation == nil) {
  239. [pendingMessage finishedProcessing];
  240. onCompletion();
  241. return;
  242. }
  243. BOOL ackNow = YES;
  244. if ([amsg isKindOfClass:[BoxTextMessage class]]) {
  245. TextMessage *message = [_entityManager.entityCreator textMessageFromBox: amsg];
  246. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:nil];
  247. } else if ([amsg isKindOfClass:[BoxImageMessage class]]) {
  248. ImageMessage *message = [_entityManager.entityCreator imageMessageFromBox:(BoxImageMessage*)amsg];
  249. NSData *fileData = nil;
  250. NSData *decryptedData = nil;
  251. NSString *filePath = [self filePath:amsg];
  252. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  253. fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];
  254. }
  255. if (fileData) {
  256. if ([message wasDeleted]) {
  257. [pendingMessage finishedProcessing];
  258. return;
  259. }
  260. message.conversation = conversation;
  261. [self decryptImageFile:fileData message:message onCompletion:^(NSData *decrypted) {
  262. NSError *error;
  263. [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
  264. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:^{
  265. if (!decrypted)
  266. [self startLoadingImageFromMessage:message boxMessage:amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  267. }];
  268. }];
  269. } else {
  270. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:^{
  271. if (!decryptedData)
  272. [self startLoadingImageFromMessage:message boxMessage:amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  273. }];
  274. }
  275. } else if ([amsg isKindOfClass:[BoxVideoMessage class]]) {
  276. [self processIncomingVideoMessage:(BoxVideoMessage*)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  277. ackNow = NO; // Only ACK video message once thumbnail has been downloaded, otherwise a failed blob download will lead to a missing message
  278. } else if ([amsg isKindOfClass:[BoxLocationMessage class]]) {
  279. LocationMessage *message = [_entityManager.entityCreator locationMessageFromBox:(BoxLocationMessage*)amsg];
  280. [self startReverserGeocodingForMessage:message];
  281. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:nil];
  282. } else if ([amsg isKindOfClass:[BoxAudioMessage class]]) {
  283. AudioMessage *message = [_entityManager.entityCreator audioMessageFromBox:(BoxAudioMessage*) amsg];
  284. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:nil];
  285. } else if ([amsg isKindOfClass:[DeliveryReceiptMessage class]]) {
  286. [self processIncomingDeliveryReceipt:(DeliveryReceiptMessage*)amsg pendingMessage:pendingMessage];
  287. } else if ([amsg isKindOfClass:[TypingIndicatorMessage class]]) {
  288. [self processIncomingTypingIndicator:(TypingIndicatorMessage*)amsg];
  289. [pendingMessage finishedProcessing];
  290. } else if ([amsg isKindOfClass:[BoxBallotCreateMessage class]]) {
  291. BallotMessageDecoder *decoder = [BallotMessageDecoder messageDecoder];
  292. BallotMessage *ballotMessage = [decoder decodeCreateBallotFromBox:(BoxBallotCreateMessage *)amsg forConversation:conversation];
  293. if (ballotMessage == nil) {
  294. NSError *error = [ThreemaError threemaError:@"Error parsing json for ballot create"];
  295. [pendingMessage finishedProcessing];
  296. onError(error);
  297. return;
  298. }
  299. [self finalizeMessage:ballotMessage inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:nil];
  300. } else if ([amsg isKindOfClass:[BoxBallotVoteMessage class]]) {
  301. [self processIncomingBallotVoteMessage:(BoxBallotVoteMessage*)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  302. ackNow = NO;
  303. } else if ([amsg isKindOfClass:[BoxFileMessage class]]) {
  304. [FileMessageDecoder decodeMessageFromBox:(BoxFileMessage *)amsg forConversation:conversation onCompletion:^(BaseMessage *message) {
  305. [self conditionallyStartLoadingFileFromMessage:(FileMessage *)message];
  306. [self finalizeMessage:message inConversation:conversation fromBoxMessage:amsg pendingMessage:pendingMessage finalizeCompletion:nil];
  307. } onError:^(NSError *err) {
  308. [pendingMessage finishedProcessing];
  309. onError(err);
  310. }];
  311. } else if ([amsg isKindOfClass:[ContactSetPhotoMessage class]]) {
  312. [self processIncomingContactSetPhotoMessage:(ContactSetPhotoMessage *)amsg conversation:(Conversation *)conversation pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  313. ackNow = NO; // Only ACK message (not blob) once contact photo has been downloaded, otherwise a failed blob download will lead to a missing message
  314. } else if ([amsg isKindOfClass:[ContactDeletePhotoMessage class]]) {
  315. [self processIncomingContactDeletePhotoMessage:(ContactDeletePhotoMessage *)amsg conversation:(Conversation *)conversation pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  316. } else if ([amsg isKindOfClass:[ContactRequestPhotoMessage class]]) {
  317. [self processIncomingContactRequestPhotoMessage:(ContactRequestPhotoMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion];
  318. } else if ([amsg isKindOfClass:[BoxVoIPCallOfferMessage class]]) {
  319. [self processIncomingVoIPCallOfferMessage:(BoxVoIPCallOfferMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  320. } else if ([amsg isKindOfClass:[BoxVoIPCallAnswerMessage class]]) {
  321. [self processIncomingVoIPCallAnswerMessage:(BoxVoIPCallAnswerMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  322. } else if ([amsg isKindOfClass:[BoxVoIPCallIceCandidatesMessage class]]) {
  323. [self processIncomingVoIPCallIceCandidatesMessage:(BoxVoIPCallIceCandidatesMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  324. } else if ([amsg isKindOfClass:[BoxVoIPCallHangupMessage class]]) {
  325. [self processIncomingVoIPCallHangupMessage:(BoxVoIPCallHangupMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  326. } else if ([amsg isKindOfClass:[BoxVoIPCallRingingMessage class]]) {
  327. [self processIncomingVoipCallRingingMessage:(BoxVoIPCallRingingMessage *)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  328. }
  329. else {
  330. DDLogError(@"Invalid message class");
  331. [pendingMessage finishedProcessing];
  332. return;
  333. }
  334. if (ackNow) {
  335. onCompletion();
  336. }
  337. }
  338. - (Conversation*)preprocessStorableMessage:(AbstractMessage*)msg {
  339. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  340. /* Try to find an existing Conversation for the same contact */
  341. // check if type allow to create the conversation
  342. Conversation *conversation = [_entityManager conversationForContact: contact createIfNotExisting:[msg canCreateConversation]];
  343. return conversation;
  344. }
  345. - (void)processIncomingGroupMessage:(AbstractGroupMessage*)amsg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  346. GroupMessageProcessor *groupProcessor = [GroupMessageProcessor groupMessageProcessorForMessage:amsg];
  347. groupProcessor.delegate = self;
  348. [groupProcessor handleMessageOnCompletion:^(BOOL didHandleMessage) {
  349. if (didHandleMessage) {
  350. Conversation *conversation = [_entityManager.entityFetcher conversationForGroupMessage:amsg];
  351. if (groupProcessor.addToPendingMessages) {
  352. [_pendingGroupMessages addObject:amsg];
  353. pendingMessage.isPendingGroupMessages = true;
  354. [pendingMessage finishedProcessing];
  355. [[NotificationManager sharedInstance] updateUnreadMessagesCount:NO];
  356. onError(nil);
  357. return;
  358. } else {
  359. if (groupProcessor.isNewGroup || !conversation) {
  360. /* process any pending group messages that could not be processed before this create */
  361. [self processPendingGroupMessages];
  362. }
  363. }
  364. [pendingMessage finishedProcessing];
  365. onCompletion();
  366. return;
  367. }
  368. // messages not handled by GroupProcessor, e.g. messages that can be processed after delayed group create
  369. Conversation *conversation = groupProcessor.conversation;
  370. if (conversation == nil) {
  371. [pendingMessage finishedProcessing];
  372. onCompletion();
  373. return;
  374. }
  375. Contact *sender = [_entityManager.entityFetcher contactForId: amsg.fromIdentity];
  376. BOOL ackNow = YES;
  377. if ([amsg isKindOfClass:[GroupRenameMessage class]]) {
  378. GroupProxy *group = [GroupProxy groupProxyForConversation:conversation];
  379. [group setName: ((GroupRenameMessage *)amsg).name remoteSentDate:amsg.date];
  380. [pendingMessage finishedProcessing];
  381. } else if ([amsg isKindOfClass:[GroupSetPhotoMessage class]]) {
  382. [self processIncomingGroupSetPhotoMessage:(GroupSetPhotoMessage*)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  383. ackNow = NO; // Only ACK message once group photo has been downloaded, otherwise a failed blob download will lead to a missing message
  384. } else if ([amsg isKindOfClass:[GroupDeletePhotoMessage class]]) {
  385. [self processIncomingGroupDeletePhotoMessage:(GroupDeletePhotoMessage*)amsg pendingMessage:pendingMessage onCompletion:onCompletion];
  386. } else if ([amsg isKindOfClass:[GroupTextMessage class]]) {
  387. TextMessage *message = [_entityManager.entityCreator textMessageFromGroupBox: (GroupTextMessage *)amsg];
  388. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:nil];
  389. } else if ([amsg isKindOfClass:[GroupLocationMessage class]]) {
  390. LocationMessage *message = [_entityManager.entityCreator locationMessageFromGroupBox:(GroupLocationMessage *)amsg];
  391. [self startReverserGeocodingForMessage:message];
  392. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:nil];
  393. } else if ([amsg isKindOfClass:[GroupImageMessage class]]) {
  394. ImageMessage *message = [_entityManager.entityCreator imageMessageFromGroupBox:(GroupImageMessage *)amsg];
  395. NSData *fileData = nil;
  396. NSData *decryptedData = nil;
  397. NSString *filePath = [self filePath:amsg];
  398. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  399. fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];
  400. }
  401. if (fileData) {
  402. if ([message wasDeleted]) {
  403. return;
  404. }
  405. message.conversation = conversation;
  406. [self decryptImageFile:fileData message:message onCompletion:^(NSData *decrypted) {
  407. NSError *error;
  408. [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
  409. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:^{
  410. if (!decrypted)
  411. [self startLoadingImageFromMessage:message boxMessage:amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  412. }];
  413. }];
  414. } else {
  415. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:^{
  416. if (!decryptedData)
  417. [self startLoadingImageFromMessage:message boxMessage:amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  418. }];
  419. }
  420. } else if ([amsg isKindOfClass:[GroupVideoMessage class]]) {
  421. [self processIncomingGroupVideoMessage:(GroupVideoMessage*)amsg conversation:conversation pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  422. ackNow = NO; // Only ACK video message once thumbnail has been downloaded, otherwise a failed blob download will lead to a missing message
  423. } else if ([amsg isKindOfClass:[GroupAudioMessage class]]) {
  424. AudioMessage *message = [_entityManager.entityCreator audioMessageFromGroupBox:(GroupAudioMessage *)amsg];
  425. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:nil];
  426. } else if ([amsg isKindOfClass:[GroupBallotCreateMessage class]]) {
  427. BallotMessageDecoder *decoder = [BallotMessageDecoder messageDecoder];
  428. BallotMessage *message = [decoder decodeCreateBallotFromGroupBox:(GroupBallotCreateMessage *)amsg forConversation:conversation];
  429. if (message == nil) {
  430. NSError *error = [ThreemaError threemaError:@"Error parsing json for ballot create"];
  431. [pendingMessage finishedProcessing];
  432. onError(error);
  433. return;
  434. }
  435. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:nil];
  436. } else if ([amsg isKindOfClass:[GroupBallotVoteMessage class]]) {
  437. [self processIncomingGroupBallotVoteMessage:(GroupBallotVoteMessage*)amsg pendingMessage:pendingMessage onCompletion:onCompletion onError:onError];
  438. ackNow = NO;
  439. } else if ([amsg isKindOfClass:[GroupFileMessage class]]) {
  440. [FileMessageDecoder decodeGroupMessageFromBox:(GroupFileMessage *)amsg forConversation:conversation onCompletion:^(BaseMessage *message) {
  441. [self finalizeGroupMessage:message inConversation:conversation fromBoxMessage:amsg sender:sender pendingMessage:pendingMessage finalizeCompletion:nil];
  442. } onError:^(NSError *err) {
  443. [pendingMessage finishedProcessing];
  444. onError(err);
  445. }];
  446. } else {
  447. DDLogError(@"Invalid message class");
  448. [pendingMessage finishedProcessing];
  449. }
  450. if (ackNow) {
  451. onCompletion();
  452. }
  453. } onError:^(NSError *error) {
  454. onError(error);
  455. }];
  456. }
  457. - (void)appendNewMessage:(BaseMessage *)message toConversation:(Conversation *)conversation {
  458. [_entityManager performSyncBlockAndSafe:^{
  459. message.conversation = conversation;
  460. if (message != nil) {
  461. conversation.lastMessage = message;
  462. }
  463. conversation.unreadMessageCount = [NSNumber numberWithInt:[[conversation unreadMessageCount] intValue] + 1];
  464. }];
  465. }
  466. - (void)finalizeMessage:(BaseMessage*)message inConversation:(Conversation*)conversation fromBoxMessage:(AbstractMessage*)boxMessage pendingMessage:(PendingMessage *)pendingMessage finalizeCompletion:(void (^) (void))finalizeCompletion {
  467. if (boxMessage.delivered && boxMessage.deliveryDate != nil) {
  468. message.delivered = boxMessage.delivered;
  469. message.deliveryDate = boxMessage.deliveryDate;
  470. } else {
  471. /* Send delivery receipt */
  472. message.delivered = [NSNumber numberWithBool:YES];
  473. message.deliveryDate = [NSDate date];
  474. [MessageSender sendDeliveryReceiptForMessage:message fromIdentity:boxMessage.fromIdentity];
  475. }
  476. [self appendNewMessage:message toConversation:conversation];
  477. [pendingMessage addBaseMessageWithMessage:message];
  478. if (boxMessage.userAck && boxMessage.sendUserAck) {
  479. if (message.userackDate == nil || message.userack.boolValue != boxMessage.userAck.boolValue) {
  480. [_entityManager performSyncBlockAndSafe:^{
  481. @try {
  482. message.read = [NSNumber numberWithBool:YES];
  483. message.readDate = [NSDate date];
  484. message.conversation.unreadMessageCount = [NSNumber numberWithInt:[[message.conversation unreadMessageCount] intValue] - 1];
  485. }
  486. @catch (NSException *exception) {
  487. // intended to catch NSObjectInaccessibleException, which may happen
  488. // if the message has been deleted in the meantime
  489. DDLogError(@"Exception while marking message as read: %@", exception);
  490. }
  491. }];
  492. if ([ServerConnector sharedServerConnector].connectionState == ConnectionStateLoggedIn) {
  493. [MessageSender sendReadReceiptForMessages:@[message] toIdentity:message.conversation.contact.identity async:NO quickReply:NO];
  494. }
  495. [_entityManager performSyncBlockAndSafe:^{
  496. if (boxMessage.userAck.boolValue) {
  497. [MessageSender sendUserAckForMessages:@[message] toIdentity:message.conversation.contact.identity async:NO quickReply:YES];
  498. message.userack = [NSNumber numberWithBool:YES];
  499. } else {
  500. [MessageSender sendUserDeclineForMessages:@[message] toIdentity:message.conversation.contact.identity async:NO quickReply:YES];
  501. message.userack = [NSNumber numberWithBool:NO];
  502. }
  503. message.userackDate = [NSDate date];
  504. }];
  505. }
  506. }
  507. if (![message isKindOfClass:[ImageMessage class]] && ![message isKindOfClass:[VideoMessage class]]) {
  508. [pendingMessage finishedProcessing];
  509. }
  510. if (finalizeCompletion != nil) {
  511. finalizeCompletion();
  512. }
  513. }
  514. - (void)finalizeGroupMessage:(BaseMessage*)message inConversation:(Conversation*)conversation fromBoxMessage:(AbstractGroupMessage*)boxMessage sender:(Contact *)sender pendingMessage:(PendingMessage *)pendingMessage finalizeCompletion:(void (^) (void))finalizeCompletion {
  515. message.sender = sender;
  516. [self appendNewMessage:message toConversation:conversation];
  517. [pendingMessage addBaseMessageWithMessage:message];
  518. if (![message isKindOfClass:[ImageMessage class]] && ![message isKindOfClass:[VideoMessage class]]) {
  519. [pendingMessage finishedProcessing];
  520. }
  521. if (finalizeCompletion != nil) {
  522. finalizeCompletion();
  523. }
  524. }
  525. - (void)startLoadingImageFromMessage:(ImageMessage*)message boxMessage:(AbstractMessage*)boxMessage pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  526. /* Start loading image */
  527. ImageMessageLoader *loader = [[ImageMessageLoader alloc] init];
  528. dispatch_async(dispatch_get_main_queue(), ^{
  529. [loader startWithMessage:message onCompletion:^(BaseMessage *message) {
  530. [pendingMessage addBaseMessageWithMessage:message];
  531. DDLogInfo(@"Image message blob load completed");
  532. if (boxMessage) {
  533. [pendingMessage finishedProcessing];
  534. }
  535. onCompletion();
  536. } onError:^(NSError *error) {
  537. DDLogError(@"Image message blob load failed with error: %@", error);
  538. if (boxMessage) {
  539. [pendingMessage finishedProcessing];
  540. }
  541. onError(error);
  542. }];
  543. });
  544. }
  545. - (void)conditionallyStartLoadingFileFromMessage:(FileMessage*)message {
  546. if ([UTIConverter isGifMimeType:message.mimeType] == YES) {
  547. // only load if not too big
  548. if (message.fileSize.floatValue > 1*1024*1024) {
  549. return;
  550. }
  551. AnimGifMessageLoader *loader = [[AnimGifMessageLoader alloc] init];
  552. [loader startWithMessage:message onCompletion:^(BaseMessage *message) {
  553. DDLogInfo(@"File message blob load completed");
  554. } onError:^(NSError *error) {
  555. DDLogError(@"File message blob load failed with error: %@", error);
  556. }];
  557. } else {
  558. if ([message renderFileImageMessage] == true || [message renderFileAudioMessage] == true) {
  559. BlobMessageLoader *loader = [[BlobMessageLoader alloc] init];
  560. [loader startWithMessage:message onCompletion:^(BaseMessage *message) {
  561. DDLogInfo(@"File message blob load completed");
  562. } onError:^(NSError *error) {
  563. DDLogError(@"File message blob load failed with error: %@", error);
  564. }];
  565. }
  566. }
  567. }
  568. - (void)processIncomingVideoMessage:(BoxVideoMessage*)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  569. __block Conversation *conversation = [self preprocessStorableMessage:msg];
  570. if (conversation == nil) {
  571. [pendingMessage finishedProcessing];
  572. onCompletion();
  573. return;
  574. }
  575. NSData *fileData = nil;
  576. NSString *filePath = [self filePath:msg];
  577. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  578. fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];
  579. }
  580. /* Conversation deleted in the meantime? */
  581. if ([conversation wasDeleted]) {
  582. /* Make a new one */
  583. conversation = [self preprocessStorableMessage:msg];
  584. if (conversation == nil) {
  585. [pendingMessage finishedProcessing];
  586. onError([ThreemaError threemaError:@"Cannot get replacement for deleted conversation"]);
  587. return;
  588. }
  589. }
  590. if (fileData) {
  591. /* Decrypt the box */
  592. NSData *thumbnailData = [[NaClCrypto sharedCrypto] symmetricDecryptData:fileData withKey:msg.encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_2 length:sizeof(kNonce_2) freeWhenDone:NO]];
  593. if (thumbnailData == nil) {
  594. [pendingMessage finishedProcessing];
  595. onError([ThreemaError threemaError:@"Video thumbnail blob decryption failed"]);
  596. return;
  597. }
  598. /* Make thumbnail */
  599. UIImage *thumbnail = [UIImage imageWithData:thumbnailData];
  600. if (thumbnail == nil) {
  601. [pendingMessage finishedProcessing];
  602. onError([ThreemaError threemaError:@"Video thumbnail decoding failed"]);
  603. return;
  604. }
  605. __block VideoMessage *message;
  606. [_entityManager performSyncBlockAndSafe:^{
  607. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  608. dbThumbnail.data = thumbnailData;
  609. dbThumbnail.width = [NSNumber numberWithInt:thumbnail.size.width];
  610. dbThumbnail.height = [NSNumber numberWithInt:thumbnail.size.height];
  611. /* Create Message in DB */
  612. message = [_entityManager.entityCreator videoMessageFromBox:msg];
  613. message.thumbnail = dbThumbnail;
  614. message.duration = [NSNumber numberWithInt:msg.duration];
  615. message.videoSize = [NSNumber numberWithInt:msg.videoSize];
  616. message.videoBlobId = msg.videoBlobId;
  617. message.encryptionKey = msg.encryptionKey;
  618. message.conversation = conversation;
  619. conversation.lastMessage = message;
  620. conversation.unreadMessageCount = [NSNumber numberWithInt:[[conversation unreadMessageCount] intValue] + 1];
  621. }];
  622. [pendingMessage addBaseMessageWithMessage:message];
  623. /* Delete thumbnail blob on server */
  624. [MessageSender markBlobAsDone:msg.thumbnailBlobId];
  625. /* Delete file from push */
  626. NSError *error;
  627. [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
  628. [pendingMessage finishedProcessing];
  629. onCompletion();
  630. } else {
  631. __block UIImage *videoPlaceholderImage = [UIImage imageNamed:@"Video"];
  632. __block NSData *videoPlaceholderImageData = UIImageJPEGRepresentation(videoPlaceholderImage, 1.0);
  633. __block VideoMessage *message;
  634. [_entityManager performSyncBlockAndSafe:^{
  635. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  636. dbThumbnail.data = videoPlaceholderImageData;
  637. dbThumbnail.width = [NSNumber numberWithInt:videoPlaceholderImage.size.width];
  638. dbThumbnail.height = [NSNumber numberWithInt:videoPlaceholderImage.size.height];
  639. /* Create Message in DB */
  640. message = [_entityManager.entityCreator videoMessageFromBox:msg];
  641. message.duration = [NSNumber numberWithInt:msg.duration];
  642. message.videoSize = [NSNumber numberWithInt:msg.videoSize];
  643. message.videoBlobId = msg.videoBlobId;
  644. message.encryptionKey = msg.encryptionKey;
  645. message.conversation = conversation;
  646. message.thumbnail = dbThumbnail;
  647. conversation.lastMessage = message;
  648. conversation.unreadMessageCount = [NSNumber numberWithInt:[[conversation unreadMessageCount] intValue] + 1];
  649. }];
  650. [pendingMessage addBaseMessageWithMessage:message];
  651. /* Send delivery receipt */
  652. [MessageSender sendDeliveryReceiptForMessage:message fromIdentity:msg.fromIdentity];
  653. /* Fetch video thumbnail */
  654. NSURLRequest *request = [BlobUtil urlRequestForBlobId:msg.thumbnailBlobId];
  655. PinnedHTTPSURLLoader *thumbnailLoader = [[PinnedHTTPSURLLoader alloc] init];
  656. [thumbnailLoader startWithURLRequest:request onCompletion:^(NSData *data) {
  657. dispatch_async(dispatch_get_main_queue(), ^{
  658. /* Decrypt the box */
  659. NSData *thumbnailData = [[NaClCrypto sharedCrypto] symmetricDecryptData:data withKey:msg.encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_2 length:sizeof(kNonce_2) freeWhenDone:NO]];
  660. if (thumbnailData == nil) {
  661. [pendingMessage finishedProcessing];
  662. onError([ThreemaError threemaError:@"Video thumbnail blob decryption failed"]);
  663. return;
  664. }
  665. /* Make thumbnail */
  666. UIImage *thumbnail = [UIImage imageWithData:thumbnailData];
  667. if (thumbnail == nil) {
  668. [pendingMessage finishedProcessing];
  669. onError([ThreemaError threemaError:@"Video thumbnail decoding failed"]);
  670. return;
  671. }
  672. [_entityManager performSyncBlockAndSafe:^{
  673. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  674. dbThumbnail.data = thumbnailData;
  675. dbThumbnail.width = [NSNumber numberWithInt:thumbnail.size.width];
  676. dbThumbnail.height = [NSNumber numberWithInt:thumbnail.size.height];
  677. /* Create Message in DB */
  678. message.thumbnail = dbThumbnail;
  679. conversation.lastMessage = message;
  680. }];
  681. [pendingMessage addBaseMessageWithMessage:message];
  682. NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
  683. conversation.objectID, kKeyObjectID,
  684. nil];
  685. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationDBRefreshedDirtyObject object:self userInfo:info];
  686. /* Delete thumbnail blob on server */
  687. [MessageSender markBlobAsDone:msg.thumbnailBlobId];
  688. [pendingMessage finishedProcessing];
  689. onCompletion();
  690. });
  691. } onError:^(NSError *error) {
  692. [pendingMessage finishedProcessing];
  693. DDLogError(@"Blob load failed: %@", error);
  694. onError(error);
  695. }];
  696. }
  697. }
  698. - (void)startReverserGeocodingForMessage:(LocationMessage*)message {
  699. /* Reverse geocoding (only necessary if there is no POI name) */
  700. if (message.poiName == nil) {
  701. double latitude = message.latitude.doubleValue;
  702. double longitude = message.longitude.doubleValue;
  703. double accuracy = message.accuracy.doubleValue;
  704. [Utils reverseGeocodeNearLatitude:latitude longitude:longitude accuracy:accuracy completion:^(NSString *label) {
  705. if ([message wasDeleted]) {
  706. return;
  707. }
  708. [_entityManager performAsyncBlockAndSafe:^{
  709. message.reverseGeocodingResult = label;
  710. }];
  711. } onError:^(NSError *error) {
  712. DDLogWarn(@"Reverse geocoding failed: %@", error);
  713. if ([message wasDeleted]) {
  714. return;
  715. }
  716. [_entityManager performAsyncBlockAndSafe:^{
  717. message.reverseGeocodingResult = [NSString stringWithFormat:@"%.5f°, %.5f°", latitude, longitude];
  718. }];
  719. }];
  720. }
  721. }
  722. - (void)processIncomingDeliveryReceipt:(DeliveryReceiptMessage*)msg pendingMessage:(PendingMessage *)pendingMessage {
  723. [_entityManager performAsyncBlockAndSafe:^{
  724. for (NSData *receiptMessageId in msg.receiptMessageIds) {
  725. /* Fetch message from DB */
  726. BaseMessage *dbmsg = [_entityManager.entityFetcher ownMessageWithId: receiptMessageId];
  727. if (dbmsg == nil) {
  728. /* This can happen if the user deletes the message before the receipt comes in */
  729. DDLogInfo(@"Cannot find message ID %@ (delivery receipt from %@)", receiptMessageId, msg.fromIdentity);
  730. continue;
  731. }
  732. if (msg.receiptType == DELIVERYRECEIPT_MSGRECEIVED) {
  733. DDLogVerbose(@"Message ID %@ has been received by recipient", receiptMessageId);
  734. dbmsg.deliveryDate = msg.date;
  735. dbmsg.delivered = [NSNumber numberWithBool:YES];
  736. } else if (msg.receiptType == DELIVERYRECEIPT_MSGREAD) {
  737. DDLogVerbose(@"Message ID %@ has been read by recipient", receiptMessageId);
  738. if (!dbmsg.delivered)
  739. dbmsg.delivered = [NSNumber numberWithBool:YES];
  740. dbmsg.readDate = msg.date;
  741. dbmsg.read = [NSNumber numberWithBool:YES];
  742. } else if (msg.receiptType == DELIVERYRECEIPT_MSGUSERACK) {
  743. DDLogVerbose(@"Message ID %@ has been user acknowledged by recipient", receiptMessageId);
  744. dbmsg.userackDate = msg.date;
  745. dbmsg.userack = [NSNumber numberWithBool:YES];
  746. } else if (msg.receiptType == DELIVERYRECEIPT_MSGUSERDECLINE) {
  747. DDLogVerbose(@"Message ID %@ has been user declined by recipient", receiptMessageId);
  748. dbmsg.userackDate = msg.date;
  749. dbmsg.userack = [NSNumber numberWithBool:NO];
  750. } else {
  751. DDLogWarn(@"Unknown delivery receipt type %d", msg.receiptType);
  752. }
  753. }
  754. [pendingMessage finishedProcessing];
  755. }];
  756. }
  757. - (void)processIncomingTypingIndicator:(TypingIndicatorMessage*)msg {
  758. [[TypingIndicatorManager sharedInstance] setTypingIndicatorForIdentity:msg.fromIdentity typing:msg.typing];
  759. }
  760. - (void)processIncomingGroupSetPhotoMessage:(GroupSetPhotoMessage*)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  761. Conversation *conversation = [_entityManager.entityFetcher conversationForGroupMessage:msg];
  762. if (conversation == nil) {
  763. DDLogInfo(@"Group ID %@ from %@ not found", msg.groupId, msg.groupCreator);
  764. [pendingMessage finishedProcessing];
  765. onCompletion();
  766. return;
  767. } else {
  768. /* Start loading image */
  769. ContactGroupPhotoLoader *loader = [[ContactGroupPhotoLoader alloc] init];
  770. [loader startWithBlobId:msg.blobId encryptionKey:msg.encryptionKey onCompletion:^(NSData *imageData) {
  771. DDLogInfo(@"Group photo blob load completed");
  772. if (conversation.managedObjectContext != nil) {
  773. /* Check if this message is older than the last set date. This ensures that we're using
  774. the latest image in case multiple images arrive for the same conversation in short succession.
  775. Must do the check here (main thread) to avoid race condition. */
  776. if (conversation.groupImageSetDate != nil && [conversation.groupImageSetDate compare:msg.date] == NSOrderedDescending) {
  777. DDLogInfo(@"Ignoring older group set photo message");
  778. [pendingMessage finishedProcessing];
  779. onCompletion();
  780. return;
  781. }
  782. UIImage *image = [UIImage imageWithData:imageData];
  783. if (image == nil) {
  784. onError([ThreemaError threemaError:@"Image decoding failed"]);
  785. [pendingMessage finishedProcessing];
  786. return;
  787. }
  788. [_entityManager performSyncBlockAndSafe:^{
  789. ImageData *dbImage = [_entityManager.entityCreator imageData];
  790. dbImage.data = imageData;
  791. dbImage.width = [NSNumber numberWithInt:image.size.width];
  792. dbImage.height = [NSNumber numberWithInt:image.size.height];
  793. conversation.groupImage = dbImage;
  794. conversation.groupImageSetDate = msg.date;
  795. }];
  796. [pendingMessage finishedProcessing];
  797. onCompletion();
  798. }
  799. } onError:^(NSError *err) {
  800. DDLogError(@"Group photo blob load failed with error: %@", err);
  801. [pendingMessage finishedProcessing];
  802. onError(err);
  803. }];
  804. }
  805. }
  806. - (void)processIncomingGroupDeletePhotoMessage:(GroupDeletePhotoMessage*)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion {
  807. Conversation *conversation = [_entityManager.entityFetcher conversationForGroupMessage:msg];
  808. if (conversation == nil) {
  809. DDLogInfo(@"Group ID %@ from %@ not found", msg.groupId, msg.groupCreator);
  810. [pendingMessage finishedProcessing];
  811. onCompletion();
  812. return;
  813. } else {
  814. if (conversation.managedObjectContext != nil) {
  815. [_entityManager performSyncBlockAndSafe:^{
  816. if (conversation.groupImage != nil) {
  817. [[_entityManager entityDestroyer] deleteObjectWithObject:conversation.groupImage];
  818. conversation.groupImage = nil;
  819. conversation.groupImageSetDate = nil;
  820. }
  821. }];
  822. [pendingMessage finishedProcessing];
  823. onCompletion();
  824. }
  825. }
  826. }
  827. - (void)processIncomingGroupVideoMessage:(GroupVideoMessage*)msg conversation:(Conversation *) conversation pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  828. NSData *fileData = nil;
  829. NSString *filePath = [self filePath:msg];
  830. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  831. fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];
  832. }
  833. Conversation *currentConversation = conversation;
  834. /* Conversation deleted in the meantime? */
  835. if ([conversation wasDeleted]) {
  836. /* Make a new one */
  837. currentConversation = [_entityManager.entityFetcher conversationForGroupMessage:msg];
  838. if (currentConversation == nil) {
  839. [pendingMessage finishedProcessing];
  840. onError([ThreemaError threemaError:@"Cannot get replacement for deleted conversation"]);
  841. return;
  842. }
  843. }
  844. if (fileData) {
  845. /* Decrypt the box */
  846. NSData *thumbnailData = [[NaClCrypto sharedCrypto] symmetricDecryptData:fileData withKey:msg.encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_2 length:sizeof(kNonce_2) freeWhenDone:NO]];
  847. if (thumbnailData == nil) {
  848. [pendingMessage finishedProcessing];
  849. onError([ThreemaError threemaError:@"Video thumbnail blob decryption failed"]);
  850. return;
  851. }
  852. /* Make thumbnail */
  853. UIImage *thumbnail = [UIImage imageWithData:thumbnailData];
  854. if (thumbnail == nil) {
  855. [pendingMessage finishedProcessing];
  856. onError([ThreemaError threemaError:@"Video thumbnail decoding failed"]);
  857. return;
  858. }
  859. __block VideoMessage *message;
  860. /* Create Message in DB */
  861. [_entityManager performSyncBlockAndSafe:^{
  862. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  863. dbThumbnail.data = thumbnailData;
  864. dbThumbnail.width = [NSNumber numberWithInt:thumbnail.size.width];
  865. dbThumbnail.height = [NSNumber numberWithInt:thumbnail.size.height];
  866. message = [_entityManager.entityCreator videoMessageFromGroupBox:msg];
  867. message.thumbnail = dbThumbnail;
  868. message.duration = [NSNumber numberWithInt:msg.duration];
  869. message.videoSize = [NSNumber numberWithInt:msg.videoSize];
  870. message.videoBlobId = msg.videoBlobId;
  871. message.encryptionKey = msg.encryptionKey;
  872. message.conversation = currentConversation;
  873. message.sender = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  874. currentConversation.lastMessage = message;
  875. currentConversation.unreadMessageCount = [NSNumber numberWithInt:[[currentConversation unreadMessageCount] intValue] + 1];
  876. }];
  877. [pendingMessage addBaseMessageWithMessage:message];
  878. /* Delete file from push */
  879. NSError *error;
  880. [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
  881. [pendingMessage finishedProcessing];
  882. onCompletion();
  883. } else {
  884. __block UIImage *videoPlaceholderImage = [UIImage imageNamed:@"Video"];
  885. __block NSData *videoPlaceholderImageData = UIImageJPEGRepresentation(videoPlaceholderImage, 1.0);
  886. __block VideoMessage *message;
  887. /* Create Message in DB */
  888. [_entityManager performSyncBlockAndSafe:^{
  889. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  890. dbThumbnail.data = videoPlaceholderImageData;
  891. dbThumbnail.width = [NSNumber numberWithInt:videoPlaceholderImage.size.width];
  892. dbThumbnail.height = [NSNumber numberWithInt:videoPlaceholderImage.size.height];
  893. message = [_entityManager.entityCreator videoMessageFromGroupBox:msg];
  894. message.thumbnail = dbThumbnail;
  895. message.duration = [NSNumber numberWithInt:msg.duration];
  896. message.videoSize = [NSNumber numberWithInt:msg.videoSize];
  897. message.videoBlobId = msg.videoBlobId;
  898. message.encryptionKey = msg.encryptionKey;
  899. message.conversation = currentConversation;
  900. message.sender = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  901. currentConversation.lastMessage = message;
  902. currentConversation.unreadMessageCount = [NSNumber numberWithInt:[[currentConversation unreadMessageCount] intValue] + 1];
  903. }];
  904. [pendingMessage addBaseMessageWithMessage:message];
  905. /* Fetch video thumbnail */
  906. NSURLRequest *request = [BlobUtil urlRequestForBlobId:msg.thumbnailBlobId];
  907. PinnedHTTPSURLLoader *thumbnailLoader = [[PinnedHTTPSURLLoader alloc] init];
  908. [thumbnailLoader startWithURLRequest:request onCompletion:^(NSData *data) {
  909. dispatch_async(dispatch_get_main_queue(), ^{
  910. /* Decrypt the box */
  911. NSData *thumbnailData = [[NaClCrypto sharedCrypto] symmetricDecryptData:data withKey:msg.encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_2 length:sizeof(kNonce_2) freeWhenDone:NO]];
  912. if (thumbnailData == nil) {
  913. [pendingMessage finishedProcessing];
  914. onError([ThreemaError threemaError:@"Video thumbnail blob decryption failed"]);
  915. return;
  916. }
  917. /* Make thumbnail */
  918. UIImage *thumbnail = [UIImage imageWithData:thumbnailData];
  919. if (thumbnail == nil) {
  920. [pendingMessage finishedProcessing];
  921. onError([ThreemaError threemaError:@"Video thumbnail decoding failed"]);
  922. return;
  923. }
  924. /* Create Message in DB */
  925. [_entityManager performSyncBlockAndSafe:^{
  926. ImageData *dbThumbnail = [_entityManager.entityCreator imageData];
  927. dbThumbnail.data = thumbnailData;
  928. dbThumbnail.width = [NSNumber numberWithInt:thumbnail.size.width];
  929. dbThumbnail.height = [NSNumber numberWithInt:thumbnail.size.height];
  930. message.thumbnail = dbThumbnail;
  931. currentConversation.lastMessage = message;
  932. }];
  933. [pendingMessage addBaseMessageWithMessage:message];
  934. [pendingMessage finishedProcessing];
  935. NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
  936. conversation.objectID, kKeyObjectID,
  937. nil];
  938. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationDBRefreshedDirtyObject object:self userInfo:info];
  939. onCompletion();
  940. });
  941. } onError:^(NSError *error) {
  942. DDLogError(@"Blob load failed: %@", error);
  943. [pendingMessage finishedProcessing];
  944. onError(error);
  945. }];
  946. }
  947. }
  948. - (void)processIncomingGroupBallotVoteMessage:(GroupBallotVoteMessage*)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  949. /* Create Message in DB */
  950. BallotMessageDecoder *decoder = [BallotMessageDecoder messageDecoder];
  951. if ([decoder decodeVoteFromGroupBox: msg] == NO) {
  952. NSError *error;
  953. error = [ThreemaError threemaError:@"Error processing ballot vote"];
  954. [pendingMessage finishedProcessing];
  955. onError(error);
  956. return;
  957. }
  958. //persist decoded data
  959. [_entityManager performAsyncBlockAndSafe:nil];
  960. [pendingMessage finishedProcessing];
  961. onCompletion();
  962. }
  963. - (void)processIncomingBallotVoteMessage:(BoxBallotVoteMessage*)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  964. /* Create Message in DB */
  965. BallotMessageDecoder *decoder = [BallotMessageDecoder messageDecoder];
  966. if ([decoder decodeVoteFromBox: msg] == NO) {
  967. NSError *error;
  968. error = [ThreemaError threemaError:@"Error parsing json for ballot vote"];
  969. [pendingMessage finishedProcessing];
  970. onError(error);
  971. return;
  972. }
  973. //persist decoded data
  974. [_entityManager performAsyncBlockAndSafe:nil];
  975. [pendingMessage finishedProcessing];
  976. onCompletion();
  977. }
  978. - (void)processPendingGroupMessages {
  979. DDLogVerbose(@"Processing pending group messages");
  980. NSArray *messages = [_pendingGroupMessages array];
  981. for (AbstractGroupMessage *msg in messages) {
  982. dispatch_async(dispatch_get_main_queue(), ^{
  983. [self processIncomingAbstractMessage:msg onCompletion:^{
  984. [_pendingGroupMessages removeObject:msg];
  985. [[ServerConnector sharedServerConnector] completedProcessingAbstractMessage:msg];
  986. } onError:^(NSError *err) {
  987. DDLogWarn(@"Processing pending group message failed: %@", err);
  988. }];
  989. });
  990. }
  991. }
  992. - (void)processIncomingContactSetPhotoMessage:(ContactSetPhotoMessage *)msg conversation:(Conversation *)conversation pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  993. /* Start loading image */
  994. ContactGroupPhotoLoader *loader = [[ContactGroupPhotoLoader alloc] init];
  995. [loader startWithBlobId:msg.blobId encryptionKey:msg.encryptionKey onCompletion:^(NSData *imageData) {
  996. DDLogInfo(@"contact photo blob load completed");
  997. ContactStore *contactStore = [ContactStore sharedContactStore];
  998. Contact *contact;
  999. if (conversation.managedObjectContext != nil) {
  1000. contact = conversation.contact;
  1001. } else {
  1002. contact = [contactStore contactForIdentity:msg.fromIdentity];
  1003. }
  1004. NSError *error;
  1005. [contactStore updateProfilePicture:contact imageData:imageData didFailWithError:&error];
  1006. if (error != nil) {
  1007. onError(error);
  1008. return;
  1009. }
  1010. [pendingMessage finishedProcessing];
  1011. onCompletion();
  1012. } onError:^(NSError *err) {
  1013. DDLogError(@"Contact photo blob load failed with error: %@", err);
  1014. [pendingMessage finishedProcessing];
  1015. if (err.code == 404)
  1016. onCompletion();
  1017. onError(err);
  1018. }];
  1019. }
  1020. - (void)processIncomingContactDeletePhotoMessage:(ContactDeletePhotoMessage *)msg conversation:(Conversation *)conversation pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1021. ContactStore *contactStore = [ContactStore sharedContactStore];
  1022. Contact *contact;
  1023. if (conversation.managedObjectContext != nil) {
  1024. contact = conversation.contact;
  1025. } else {
  1026. contact = [contactStore contactForIdentity:msg.fromIdentity];
  1027. }
  1028. [contactStore deleteProfilePicture:contact];
  1029. [pendingMessage finishedProcessing];
  1030. onCompletion();
  1031. }
  1032. - (void)processIncomingContactRequestPhotoMessage:(ContactRequestPhotoMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion {
  1033. [[ContactStore sharedContactStore] removeProfilePictureFlagForContact:msg.fromIdentity];
  1034. [pendingMessage finishedProcessing];
  1035. onCompletion();
  1036. }
  1037. - (void)processIncomingVoIPCallOfferMessage:(BoxVoIPCallOfferMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1038. VoIPCallMessageDecoder *decoder = [VoIPCallMessageDecoder messageDecoder];
  1039. VoIPCallOfferMessage *message = [decoder decodeVoIPCallOfferFromBox:msg];
  1040. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  1041. if (message == nil) {
  1042. NSError *error;
  1043. error = [ThreemaError threemaError:@"Error parsing json for voip call offer"];
  1044. [pendingMessage finishedProcessing];
  1045. onError(error);
  1046. return;
  1047. }
  1048. [[VoIPCallStateManager shared] incomingCallOfferWithOffer:message contact:contact completion:^{
  1049. [pendingMessage finishedProcessing];
  1050. onCompletion();
  1051. }];
  1052. }
  1053. - (void)processIncomingVoIPCallAnswerMessage:(BoxVoIPCallAnswerMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1054. VoIPCallMessageDecoder *decoder = [VoIPCallMessageDecoder messageDecoder];
  1055. VoIPCallAnswerMessage *message = [decoder decodeVoIPCallAnswerFromBox:msg];
  1056. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  1057. if (message == nil) {
  1058. NSError *error;
  1059. error = [ThreemaError threemaError:@"Error parsing json for ballot vote"];
  1060. [pendingMessage finishedProcessing];
  1061. onError(error);
  1062. return;
  1063. }
  1064. [[VoIPCallStateManager shared] incomingCallAnswerWithAnswer:message contact:contact completion:^{
  1065. [pendingMessage finishedProcessing];
  1066. onCompletion();
  1067. }];
  1068. }
  1069. - (void)processIncomingVoIPCallIceCandidatesMessage:(BoxVoIPCallIceCandidatesMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1070. VoIPCallMessageDecoder *decoder = [VoIPCallMessageDecoder messageDecoder];
  1071. VoIPCallIceCandidatesMessage *message = [decoder decodeVoIPCallIceCandidatesFromBox:msg];
  1072. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  1073. if (message == nil) {
  1074. NSError *error;
  1075. error = [ThreemaError threemaError:@"Error parsing json for ice candidates"];
  1076. [pendingMessage finishedProcessing];
  1077. onError(error);
  1078. return;
  1079. }
  1080. [[VoIPCallStateManager shared] incomingIceCandidatesWithCandidates:message contact:contact completion:^{
  1081. [pendingMessage finishedProcessing];
  1082. onCompletion();
  1083. }];
  1084. [pendingMessage finishedProcessing];
  1085. onCompletion();
  1086. }
  1087. - (void)processIncomingVoIPCallHangupMessage:(BoxVoIPCallHangupMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1088. VoIPCallMessageDecoder *decoder = [VoIPCallMessageDecoder messageDecoder];
  1089. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  1090. VoIPCallHangupMessage *message = [decoder decodeVoIPCallHangupFromBox:msg contact:contact];
  1091. if (message == nil) {
  1092. NSError *error;
  1093. error = [ThreemaError threemaError:@"Error parsing json for hangup"];
  1094. [pendingMessage finishedProcessing];
  1095. onError(error);
  1096. return;
  1097. }
  1098. [[VoIPCallStateManager shared] incomingCallHangupWithHangup:message];
  1099. [pendingMessage finishedProcessing];
  1100. onCompletion();
  1101. }
  1102. - (void)processIncomingVoipCallRingingMessage:(BoxVoIPCallRingingMessage *)msg pendingMessage:(PendingMessage *)pendingMessage onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *err))onError {
  1103. VoIPCallMessageDecoder *decoder = [VoIPCallMessageDecoder messageDecoder];
  1104. Contact *contact = [_entityManager.entityFetcher contactForId: msg.fromIdentity];
  1105. VoIPCallRingingMessage *message = [decoder decodeVoIPCallRingingFromBox:msg contact:contact];
  1106. if (message == nil) {
  1107. NSError *error;
  1108. error = [ThreemaError threemaError:@"Error parsing json for ringing"];
  1109. [pendingMessage finishedProcessing];
  1110. onError(error);
  1111. return;
  1112. }
  1113. [[VoIPCallStateManager shared] incomingCallRingingWithRinging:message];
  1114. [pendingMessage finishedProcessing];
  1115. onCompletion();
  1116. }
  1117. - (NSString *)filePath:(AbstractMessage *)message {
  1118. NSString *groupDocumentsPath = [DocumentManager groupDocumentsDirectory].path;
  1119. NSString *name = [NSString stringWithFormat:@"PushImage_%@", [NSString stringWithHexData:message.messageId]];
  1120. NSString *fileName = [NSString stringWithFormat:@"/%@.jpg", name];
  1121. return [groupDocumentsPath stringByAppendingString:fileName];
  1122. }
  1123. - (void)decryptImageFile:(NSData *)data message:(ImageMessage *)message onCompletion:(void(^)(NSData *decrypted))onCompletion {
  1124. NSData *decryptedData = nil;
  1125. ImageMessageLoader *loader = [[ImageMessageLoader alloc] init];
  1126. NSData *encryptionKey = [message blobGetEncryptionKey];
  1127. if (encryptionKey == nil) {
  1128. // handle image message backward compatibility
  1129. if ([message isKindOfClass:[ImageMessage class]]) {
  1130. if (((ImageMessage *)message).imageNonce == nil) {
  1131. DDLogWarn(@"Missing image encryption key or nonce!");
  1132. onCompletion(nil);
  1133. }
  1134. } else {
  1135. DDLogWarn(@"Missing encryption key!");
  1136. onCompletion(nil);
  1137. }
  1138. }
  1139. loader.message = message;
  1140. decryptedData = [loader decryptData:data];
  1141. if (decryptedData != nil) {
  1142. [loader updateDBObjectWithData:decryptedData onCompletion:^{
  1143. if (message.conversation.groupId == nil) {
  1144. [MessageSender markBlobAsDone:message.imageBlobId];
  1145. }
  1146. DDLogInfo(@"Blob successfully downloaded (%lu bytes)", (unsigned long)data.length);
  1147. onCompletion(decryptedData);
  1148. }];
  1149. } else {
  1150. onCompletion(decryptedData);
  1151. }
  1152. }
  1153. - (void)startProcessPendingGroupMessages {
  1154. [self processPendingGroupMessages];
  1155. }
  1156. @end