AbstractMessage.m 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 "AbstractMessage.h"
  21. #import "NaClCrypto.h"
  22. #import "EntityManager.h"
  23. #import "MyIdentityStore.h"
  24. #import "ProtocolDefines.h"
  25. #import "Contact.h"
  26. #import "BoxFileMessage.h"
  27. #import "BallotMessageDecoder.h"
  28. #import "FileMessageDecoder.h"
  29. #import "BundleUtil.h"
  30. #import "QuoteParser.h"
  31. #import "TextStyleUtils.h"
  32. #import "NSString+Hex.h"
  33. #import "Utils.h"
  34. #import "NonceHasher.h"
  35. #ifdef DEBUG
  36. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  37. #else
  38. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  39. #endif
  40. @implementation AbstractMessage
  41. - (id)init
  42. {
  43. self = [super init];
  44. if (self) {
  45. self.date = [NSDate date];
  46. self.messageId = [AbstractMessage randomMessageId];
  47. }
  48. return self;
  49. }
  50. - (BoxedMessage*)makeBox {
  51. /* prepare data for box */
  52. uint8_t type = self.type;
  53. NSData *_body = self.body;
  54. NSMutableData *boxData = [NSMutableData dataWithCapacity:_body.length + 1];
  55. [boxData appendBytes:&type length:1];
  56. [boxData appendData:_body];
  57. /* PKCS7 padding */
  58. NSData *padAmount = [[NaClCrypto sharedCrypto] randomBytes:1];
  59. uint8_t padbytes = *((uint8_t*)padAmount.bytes);
  60. if (padbytes == 0)
  61. padbytes = 1;
  62. if ((1 + _body.length + padbytes) < kMinMessagePaddedLen)
  63. padbytes = kMinMessagePaddedLen - 1 - _body.length;
  64. DDLogVerbose(@"Adding %d padding bytes", padbytes);
  65. uint8_t *paddata = malloc(padbytes);
  66. if (!paddata)
  67. return nil;
  68. for (int i = 0; i < padbytes; i++)
  69. paddata[i] = padbytes;
  70. [boxData appendData:[NSData dataWithBytesNoCopy:paddata length:padbytes]];
  71. /* obtain receiver's key */
  72. __block Contact *contact;
  73. __block BOOL isValid;
  74. __block NSData *receiverPublicKey;
  75. EntityManager *entityManager = [[EntityManager alloc] init];
  76. [entityManager performBlockAndWait:^{
  77. contact = [entityManager.entityFetcher contactForId:self.toIdentity];
  78. isValid = contact.isValid;
  79. receiverPublicKey = contact.publicKey;
  80. }];
  81. if (contact == nil) {
  82. DDLogError(@"Contact not found for identity %@", self.toIdentity);
  83. return nil;
  84. }
  85. if (isValid == NO) {
  86. DDLogInfo(@"Dropping message to invalid identity %@", self.toIdentity);
  87. return nil;
  88. }
  89. if (receiverPublicKey == nil) {
  90. DDLogError(@"Cannot get public key for identity %@", self.toIdentity);
  91. return nil;
  92. }
  93. /* make random nonce and save to database */
  94. NSData *nonce = [[NaClCrypto sharedCrypto] randomBytes:kNaClCryptoNonceSize];
  95. if (!self.immediate) {
  96. [entityManager performAsyncBlockAndSafe:^{
  97. [entityManager.entityCreator nonceWithData:[NonceHasher hashedNonce:nonce]];
  98. }];
  99. }
  100. /* sign/encrypt with our secret key */
  101. NSData *boxedData = [[MyIdentityStore sharedMyIdentityStore] encryptData:boxData withNonce:nonce publicKey:receiverPublicKey];
  102. BoxedMessage *boxmsg = [[BoxedMessage alloc] init];
  103. boxmsg.fromIdentity = [MyIdentityStore sharedMyIdentityStore].identity;
  104. boxmsg.toIdentity = self.toIdentity;
  105. boxmsg.messageId = self.messageId;
  106. boxmsg.date = self.date;
  107. boxmsg.flags = 0;
  108. if (self.shouldPush)
  109. boxmsg.flags |= MESSAGE_FLAG_PUSH;
  110. if (self.immediate)
  111. boxmsg.flags |= MESSAGE_FLAG_IMMEDIATE;
  112. if (self.noAck)
  113. boxmsg.flags |= MESSAGE_FLAG_NOACK;
  114. if (self.isGroup)
  115. boxmsg.flags |= MESSAGE_FLAG_GROUP;
  116. if (self.isVoIP)
  117. boxmsg.flags |= MESSAGE_FLAG_VOIP;
  118. boxmsg.pushFromName = [MyIdentityStore sharedMyIdentityStore].pushFromName;
  119. boxmsg.nonce = nonce;
  120. boxmsg.box = boxedData;
  121. return boxmsg;
  122. }
  123. + (NSData*)randomMessageId {
  124. return [[NaClCrypto sharedCrypto] randomBytes:kMessageIdLen];
  125. }
  126. - (uint8_t)type {
  127. return 0;
  128. }
  129. - (NSData*)body {
  130. return nil;
  131. }
  132. - (BOOL)canCreateConversation {
  133. return YES;
  134. }
  135. - (BOOL)needsConversation {
  136. return YES;
  137. }
  138. - (BOOL)shouldPush {
  139. return NO;
  140. }
  141. - (BOOL)immediate {
  142. return NO;
  143. }
  144. - (BOOL)noAck {
  145. return NO;
  146. }
  147. - (BOOL)isGroup {
  148. return NO;
  149. }
  150. - (BOOL)isVoIP {
  151. return NO;
  152. }
  153. - (BOOL)isContentValid {
  154. //method must be implemented by subclass
  155. [NSException raise:NSInternalInconsistencyException
  156. format:@"Method %@ is abstract, subclass it", NSStringFromSelector(_cmd)];
  157. return NO;
  158. }
  159. - (NSString *)description {
  160. return [NSString stringWithFormat:@"%@ - msgId: %@, from: %@, to: %@", NSStringFromClass([self class]), _messageId, _fromIdentity, _toIdentity];
  161. }
  162. - (NSString *)pushNotificationBody {
  163. NSString *body = [NSString new];
  164. if ([self isKindOfClass:[BoxTextMessage class]]) {
  165. NSString *quotedIdentity = nil;
  166. NSString *remainingBody = nil;
  167. NSString *quotedText = [QuoteParser parseQuoteFromMessage:((BoxTextMessage *)self).text quotedIdentity:&quotedIdentity remainingBody:&remainingBody];
  168. if (quotedText) {
  169. body = remainingBody;
  170. } else {
  171. body = ((BoxTextMessage *)self).text;
  172. }
  173. body = [TextStyleUtils makeMentionsStringForText:body];
  174. }
  175. else if ([self isKindOfClass:[BoxImageMessage class]]) {
  176. body = [BundleUtil localizedStringForKey:@"new_image_message"];
  177. }
  178. else if ([self isKindOfClass:[BoxVideoMessage class]]) {
  179. body = [BundleUtil localizedStringForKey:@"new_video_message"];
  180. }
  181. else if ([self isKindOfClass:[BoxLocationMessage class]]) {
  182. NSString *locationName = [(BoxLocationMessage *)self poiName];
  183. if (locationName)
  184. body = [NSString stringWithFormat:@"%@: %@", [BundleUtil localizedStringForKey:@"new_location_message"], locationName];
  185. else
  186. body = [BundleUtil localizedStringForKey:@"new_location_message"];
  187. }
  188. else if ([self isKindOfClass:[BoxAudioMessage class]]) {
  189. body = [NSString stringWithFormat:@"%@ (%@)", [BundleUtil localizedStringForKey:@"new_audio_message"], [Utils timeStringForSeconds:((BoxAudioMessage *)self).duration]];
  190. }
  191. else if ([self isKindOfClass:[BoxBallotCreateMessage class]]) {
  192. BallotMessageDecoder *decoder = [BallotMessageDecoder messageDecoder];
  193. BOOL closed = [decoder decodeNotificationCreateBallotStateFromBox:(BoxBallotCreateMessage *)self].integerValue == kBallotStateClosed;
  194. NSString *ballotTitle = [decoder decodeCreateBallotTitleFromBox:(BoxBallotCreateMessage *)self];
  195. if (closed) {
  196. body = [BundleUtil localizedStringForKey:@"new_ballot_closed_message"];
  197. } else {
  198. body = [NSString stringWithFormat:[BundleUtil localizedStringForKey:@"new_ballot_create_message"], ballotTitle];
  199. }
  200. }
  201. else if ([self isKindOfClass:[BoxFileMessage class]]) {
  202. NSString *caption = [FileMessageDecoder decodeFileCaptionFromBox:(BoxFileMessage *)self];
  203. if (caption != nil) {
  204. body = caption;
  205. } else {
  206. NSString *fileName = [FileMessageDecoder decodeFilenameFromBox:(BoxFileMessage *)self];
  207. body = [NSString stringWithFormat:[BundleUtil localizedStringForKey:@"new_file_message"], fileName];
  208. }
  209. }
  210. return body;
  211. }
  212. - (BOOL)allowToSendProfilePicture {
  213. return NO;
  214. }
  215. - (NSString *)getMessageIdString {
  216. return [NSString stringWithHexData:self.messageId];
  217. }
  218. #pragma mark - NSCoding
  219. - (id)initWithCoder:(NSCoder *)decoder {
  220. if (self = [super init]) {
  221. self.fromIdentity = [decoder decodeObjectForKey:@"fromIdentity"];
  222. self.toIdentity = [decoder decodeObjectForKey:@"toIdentity"];
  223. self.messageId = [decoder decodeObjectForKey:@"messageId"];
  224. self.pushFromName = [decoder decodeObjectForKey:@"pushFromName"];
  225. self.date = [decoder decodeObjectForKey:@"date"];
  226. self.deliveryDate = [decoder decodeObjectForKey:@"deliveryDate"];
  227. self.delivered = [decoder decodeObjectForKey:@"delivered"];
  228. self.userAck = [decoder decodeObjectForKey:@"userAck"];
  229. self.sendUserAck = [decoder decodeObjectForKey:@"sendUserAck"];
  230. self.nonce = [decoder decodeObjectForKey:@"nonce"];
  231. self.receivedAfterInitialQueueSend = [decoder decodeBoolForKey:@"receivedAfterInitialQueueSend"];
  232. self.flags = [decoder decodeObjectForKey:@"flags"];
  233. }
  234. return self;
  235. }
  236. - (void)encodeWithCoder:(NSCoder *)encoder {
  237. [encoder encodeObject:self.fromIdentity forKey:@"fromIdentity"];
  238. [encoder encodeObject:self.toIdentity forKey:@"toIdentity"];
  239. [encoder encodeObject:self.messageId forKey:@"messageId"];
  240. [encoder encodeObject:self.pushFromName forKey:@"pushFromName"];
  241. [encoder encodeObject:self.date forKey:@"date"];
  242. [encoder encodeObject:self.deliveryDate forKey:@"deliveryDate"];
  243. [encoder encodeObject:self.delivered forKey:@"delivered"];
  244. [encoder encodeObject:self.userAck forKey:@"userAck"];
  245. [encoder encodeObject:self.sendUserAck forKey:@"sendUserAck"];
  246. [encoder encodeObject:self.nonce forKey:@"nonce"];
  247. [encoder encodeBool:self.receivedAfterInitialQueueSend forKey:@"receivedAfterInitialQueueSend"];
  248. [encoder encodeObject:self.flags forKey:@"flags"];
  249. }
  250. @end