chatsecureios / ChatSecure / Classes / Controllers / OTREncryptionManager.m @ 8d76e2e3
History | View | Annotate | Download (34.8 KB)
1 |
// |
---|---|
2 |
// OTREncryptionManager.m |
3 |
// Off the Record |
4 |
// |
5 |
// Created by Chris Ballinger on 9/4/11. |
6 |
// Copyright (c) 2011 Chris Ballinger. All rights reserved. |
7 |
// |
8 |
// This file is part of ChatSecure. |
9 |
// |
10 |
// ChatSecure is free software: you can redistribute it and/or modify |
11 |
// it under the terms of the GNU General Public License as published by |
12 |
// the Free Software Foundation, either version 3 of the License, or |
13 |
// (at your option) any later version. |
14 |
// |
15 |
// ChatSecure is distributed in the hope that it will be useful, |
16 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
// GNU General Public License for more details. |
19 |
// |
20 |
// You should have received a copy of the GNU General Public License |
21 |
// along with ChatSecure. If not, see <http://www.gnu.org/licenses/>. |
22 |
|
23 |
#import "OTREncryptionManager.h" |
24 |
#import "OTRIncomingMessage.h" |
25 |
#import "OTROutgoingMessage.h" |
26 |
#import "OTRBuddy.h" |
27 |
#import "OTRAccount.h" |
28 |
#import "OTRProtocolManager.h" |
29 |
#import "OTRDatabaseManager.h" |
30 |
#import "OTRUtilities.h" |
31 |
@import OTRAssets; |
32 |
#import "OTRAppDelegate.h" |
33 |
#import "OTRMessagesHoldTalkViewController.h" |
34 |
#import "UIViewController+ChatSecure.h" |
35 |
#import "OTRImageItem.h" |
36 |
#import "OTRAudioItem.h" |
37 |
#import "OTRVideoItem.h" |
38 |
#import "OTRMediaFileManager.h" |
39 |
#import "OTRMediaServer.h" |
40 |
#import "OTRDatabaseManager.h" |
41 |
#import "OTRLog.h" |
42 |
#import "OTRPushTLVHandler.h" |
43 |
#import "OTRXMPPManager.h" |
44 |
#import "OTRYapMessageSendAction.h" |
45 |
#import <ChatSecureCore/ChatSecureCore-Swift.h> |
46 |
|
47 |
@import AVFoundation; |
48 |
@import XMPPFramework; |
49 |
@import OTRAssets; |
50 |
|
51 |
NSString *const OTRMessageStateDidChangeNotification = @"OTREncryptionManagerMessageStateDidChangeNotification"; |
52 |
NSString *const OTRWillStartGeneratingPrivateKeyNotification = @"OTREncryptionManagerWillStartGeneratingPrivateKeyNotification"; |
53 |
NSString *const OTRDidFinishGeneratingPrivateKeyNotification = @"OTREncryptionManagerdidFinishGeneratingPrivateKeyNotification"; |
54 |
NSString *const OTRMessageStateKey = @"OTREncryptionManagerMessageStateKey"; |
55 |
|
56 |
@interface OTREncryptionManager () <OTRKitDelegate, OTRDataHandlerDelegate> |
57 |
@property (nonatomic, strong) OTRKit *otrKit; |
58 |
@property (nonatomic, strong) NSCache *otrFingerprintCache; |
59 |
@end |
60 |
|
61 |
@implementation OTREncryptionManager |
62 |
|
63 |
|
64 |
- (id) init { |
65 |
if (self = [super init]) { |
66 |
_otrFingerprintCache = [[NSCache alloc] init]; |
67 |
_otrKit = [[OTRKit alloc] initWithDelegate:self dataPath:nil]; |
68 |
_dataHandler = [[OTRDataHandler alloc] initWithOTRKit:self.otrKit delegate:self]; |
69 |
_pushTLVHandler = [[OTRPushTLVHandler alloc] initWithOTRKit:self.otrKit delegate:nil]; |
70 |
NSArray *protectPaths = @[self.otrKit.privateKeyPath, self.otrKit.fingerprintsPath, self.otrKit.instanceTagsPath]; |
71 |
for (NSString *path in protectPaths) { |
72 |
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { |
73 |
[@"" writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil]; |
74 |
} |
75 |
[OTREncryptionManager setFileProtection:NSFileProtectionCompleteUntilFirstUserAuthentication path:path]; |
76 |
[OTREncryptionManager addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:path]]; |
77 |
} |
78 |
self.otrKit.otrPolicy = OTRKitPolicyOpportunistic; |
79 |
} |
80 |
return self; |
81 |
} |
82 |
|
83 |
- (OTRProtocolType)prototcolTypeForString:(NSString *)typeString |
84 |
{ |
85 |
if ([typeString isEqualToString:kOTRProtocolTypeXMPP]) |
86 |
{ |
87 |
return OTRProtocolTypeXMPP; |
88 |
} |
89 |
else { |
90 |
return OTRProtocolTypeNone; |
91 |
} |
92 |
} |
93 |
|
94 |
- (void)maybeRefreshOTRSessionForBuddyKey:(NSString *)buddyKey collection:(NSString *)collection { |
95 |
__block OTRBuddy *buddy = nil; |
96 |
__block OTRAccount *account = nil; |
97 |
__block BOOL hasOMEMODevices = NO; |
98 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
99 |
id databaseObject = [transaction objectForKey:buddyKey inCollection:collection]; |
100 |
if ([databaseObject isKindOfClass:[OTRBuddy class]]) { |
101 |
buddy = databaseObject; |
102 |
account = [buddy accountWithTransaction:transaction]; |
103 |
} |
104 |
hasOMEMODevices = [OTROMEMODevice allDevicesForParentKey:buddyKey collection:collection transaction:transaction].count > 0; |
105 |
} completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) completionBlock:^{ |
106 |
|
107 |
if (buddy == nil || account == nil) { |
108 |
return; |
109 |
} |
110 |
|
111 |
if (buddy.currentStatus == OTRThreadStatusOffline) { |
112 |
//If the buddy if offline then don't try to start the session up |
113 |
return; |
114 |
} |
115 |
|
116 |
// Exit if OTRSessionSecurity is not set to use OTR |
117 |
if (buddy.preferredSecurity != OTRSessionSecurityOTR) { |
118 |
return; |
119 |
} |
120 |
|
121 |
NSArray<OTRFingerprint *>*fingerprints = [self.otrKit fingerprintsForUsername:buddy.username accountName:account.username protocol:account.protocolTypeString]; |
122 |
if ([fingerprints count] > 0 || hasOMEMODevices) { |
123 |
OTRKitMessageState messageState = [self.otrKit messageStateForUsername:buddy.username accountName:account.username protocol:account.protocolTypeString]; |
124 |
if (messageState != OTRKitMessageStateEncrypted) { |
125 |
[self.otrKit initiateEncryptionWithUsername:buddy.username accountName:account.username protocol:account.protocolTypeString]; |
126 |
} |
127 |
} |
128 |
}]; |
129 |
} |
130 |
|
131 |
- (NSString *)cacheKeyForYapKey:(NSString *)key collection:(NSString *)collection fingerprint:(NSData *)data |
132 |
{ |
133 |
return [NSString stringWithFormat:@"%@%@%@",key,collection,@([data hash])]; |
134 |
} |
135 |
|
136 |
- (OTRTrustLevel)otrFetchTrustForUsername:(NSString*)username |
137 |
accountName:(NSString*)accountName |
138 |
protocol:(NSString*)protocol |
139 |
fingerprint:(NSData *)fingerprintData |
140 |
{ |
141 |
NSArray<OTRFingerprint*>*fingerprints = [self.otrKit fingerprintsForUsername:username accountName:accountName protocol:protocol]; |
142 |
__block OTRTrustLevel trust = OTRTrustLevelUnknown; |
143 |
[fingerprints enumerateObjectsUsingBlock:^(OTRFingerprint * _Nonnull finger, NSUInteger idx, BOOL * _Nonnull stop) { |
144 |
if ([finger.fingerprint isEqualToData:fingerprintData]) { |
145 |
trust = finger.trustLevel; |
146 |
*stop = YES; |
147 |
} |
148 |
}]; |
149 |
|
150 |
return trust; |
151 |
} |
152 |
|
153 |
- (OTRFingerprint *)otrFingerprintForKey:(NSString *)key collection:(NSString *)collection fingerprint:(NSData *)fingerprint; |
154 |
{ |
155 |
NSString *cacheKey = [self cacheKeyForYapKey:key collection:collection fingerprint:fingerprint]; |
156 |
NSNumber *resultNumber = [self.otrFingerprintCache objectForKey:cacheKey]; |
157 |
OTRTrustLevel trust = OTRTrustLevelUnknown; |
158 |
__block OTRBuddy *buddy = nil; |
159 |
__block OTRAccount *account = nil; |
160 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
161 |
buddy = [transaction objectForKey:key inCollection:collection]; |
162 |
account = [buddy accountWithTransaction:transaction]; |
163 |
}]; |
164 |
|
165 |
if (!buddy || !account) { |
166 |
return nil; |
167 |
} |
168 |
|
169 |
if (resultNumber == nil) { |
170 |
trust = [self otrFetchTrustForUsername:buddy.username accountName:account.username protocol:account.protocolTypeString fingerprint:fingerprint]; |
171 |
// No point in saving uknown trust to the cache. This might cause issues with the cach not being invalidated properly. |
172 |
if (trust != OTRTrustLevelUnknown) { |
173 |
[self.otrFingerprintCache setObject:@(trust) forKey:cacheKey]; |
174 |
} |
175 |
|
176 |
} else { |
177 |
trust = resultNumber.unsignedIntegerValue; |
178 |
} |
179 |
|
180 |
return [[OTRFingerprint alloc] initWithUsername:buddy.username accountName:account.username protocol:account.protocolTypeString fingerprint:fingerprint trustLevel:trust]; |
181 |
} |
182 |
|
183 |
- (void)saveFingerprint:(OTRFingerprint *)fingerprint; |
184 |
{ |
185 |
__block OTRBuddy *buddy = nil; |
186 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
187 |
buddy = [self buddyForFingerprint:fingerprint transaction:transaction]; |
188 |
}]; |
189 |
[self.otrFingerprintCache setObject:@(fingerprint.trustLevel) forKey:[self cacheKeyForYapKey:buddy.uniqueId collection:[buddy.class collection] fingerprint:fingerprint.fingerprint]]; |
190 |
|
191 |
[self.otrKit saveFingerprint:fingerprint]; |
192 |
} |
193 |
|
194 |
- (BOOL)removeOTRFingerprint:(OTRFingerprint *)fingerprint error:( NSError * _Nullable *)error; |
195 |
{ |
196 |
__block OTRXMPPBuddy *buddy = nil; |
197 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
198 |
buddy = [self buddyForFingerprint:fingerprint transaction:transaction]; |
199 |
}]; |
200 |
|
201 |
if (!buddy) { |
202 |
return false; |
203 |
} |
204 |
|
205 |
NSString *cacheKey = [self cacheKeyForYapKey:buddy.uniqueId collection:[buddy.class collection] fingerprint:fingerprint.fingerprint]; |
206 |
[self.otrFingerprintCache removeObjectForKey:cacheKey]; |
207 |
|
208 |
return [self.otrKit deleteFingerprint:fingerprint error:error]; |
209 |
} |
210 |
|
211 |
- (nullable OTRXMPPBuddy*) buddyForFingerprint:(OTRFingerprint*)fingerprint transaction:(YapDatabaseReadTransaction*)transaction { |
212 |
return [self buddyForUsername:fingerprint.username accountName:fingerprint.accountName transaction:transaction]; |
213 |
} |
214 |
|
215 |
- (nullable OTRXMPPBuddy*) buddyForUsername:(NSString*)username accountName:(NSString*)accountName transaction:(YapDatabaseReadTransaction*)transaction { |
216 |
XMPPJID *jid = [XMPPJID jidWithString:username]; |
217 |
if (!jid) { |
218 |
DDLogWarn(@"OTRKitDelegate: not a valid JID: %@ %@", username, accountName); |
219 |
return nil; |
220 |
} |
221 |
OTRAccount *account = [OTRAccount allAccountsWithUsername:accountName transaction:transaction].firstObject; |
222 |
if (!account) { |
223 |
DDLogWarn(@"OTRKitDelegate: Account not found for %@ %@", username, accountName); |
224 |
return nil; |
225 |
} |
226 |
OTRXMPPBuddy *buddy = [OTRXMPPBuddy fetchBuddyWithJid:jid accountUniqueId:account.uniqueId transaction:transaction]; |
227 |
if (!buddy) { |
228 |
DDLogWarn(@"OTRKitDelegate: Buddy not found for %@ %@", username, accountName); |
229 |
return nil; |
230 |
} |
231 |
return buddy; |
232 |
} |
233 |
|
234 |
|
235 |
#pragma mark OTRKitDelegate methods |
236 |
|
237 |
- (void)otrKit:(OTRKit *)otrKit injectMessage:(NSString *)text username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol fingerprint:(OTRFingerprint *)fingerprint tag:(id)tag |
238 |
{ |
239 |
//only otrproltocol |
240 |
OTROutgoingMessage *message = [[OTROutgoingMessage alloc] init]; |
241 |
message.text =text; |
242 |
|
243 |
__block OTRBuddy *buddy = nil; |
244 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { |
245 |
buddy = [self buddyForUsername:username accountName:accountName transaction:transaction]; |
246 |
} completionBlock:^{ |
247 |
if (!buddy) { return; } |
248 |
message.buddyUniqueId = buddy.uniqueId; |
249 |
[[OTRProtocolManager sharedInstance] sendMessage:message]; |
250 |
}]; |
251 |
} |
252 |
|
253 |
- (void)otrKit:(OTRKit *)otrKit encodedMessage:(NSString *)encodedMessage wasEncrypted:(BOOL)wasEncrypted username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol fingerprint:(OTRFingerprint *)fingerprint tag:(id)tag error:(NSError *)error |
254 |
{ |
255 |
if (error) { |
256 |
DDLogError(@"Encode Error: %@",error); |
257 |
} |
258 |
|
259 |
|
260 |
// |
261 |
if ([tag isKindOfClass:[OTRBaseMessage class]]) { |
262 |
OTRBaseMessage *message = nil; |
263 |
message = [tag copy]; |
264 |
|
265 |
// When replying to OTRDATA requests, we pass along the tag |
266 |
// of the original incoming message. We don't want to actually show these messages in the chat |
267 |
// so if we detect an incoming message in the encodedMessage callback we should just send the encoded data. |
268 |
if ([message isKindOfClass:[OTRIncomingMessage class]]) { |
269 |
OTROutgoingMessage *otrDataMessage = [[OTROutgoingMessage alloc] init]; |
270 |
otrDataMessage.buddyUniqueId = message.buddyUniqueId; |
271 |
otrDataMessage.text = encodedMessage; |
272 |
[[OTRProtocolManager sharedInstance] sendMessage:otrDataMessage]; |
273 |
return; |
274 |
} else if ([message isKindOfClass:[OTROutgoingMessage class]]) { |
275 |
OTROutgoingMessage *outgoingMessage = (OTROutgoingMessage *)message; |
276 |
if (error) { |
277 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
278 |
OTROutgoingMessage *dbMessage = [[transaction objectForKey:outgoingMessage.uniqueId inCollection:[OTROutgoingMessage collection]] copy]; |
279 |
dbMessage.error = error; |
280 |
[dbMessage saveWithTransaction:transaction]; |
281 |
// Need to make sure any sending action associated with this message is removed |
282 |
NSString * actionKey = [OTRYapMessageSendAction actionKeyForMessageKey:dbMessage.uniqueId messageCollection:[OTROutgoingMessage collection]]; |
283 |
[transaction removeObjectForKey:actionKey inCollection:[OTRYapMessageSendAction collection]]; |
284 |
}]; |
285 |
} |
286 |
else if ([encodedMessage length]) { |
287 |
if (wasEncrypted && fingerprint != nil) { |
288 |
outgoingMessage.messageSecurityInfo = [[OTRMessageEncryptionInfo alloc] initWithOTRFingerprint:fingerprint.fingerprint]; |
289 |
} |
290 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
291 |
[message saveWithTransaction:transaction]; |
292 |
} completionBlock:^{ |
293 |
OTROutgoingMessage *newEncodedMessage = [outgoingMessage copy]; |
294 |
newEncodedMessage.text = encodedMessage; |
295 |
[[OTRProtocolManager sharedInstance] sendMessage:newEncodedMessage]; |
296 |
}]; |
297 |
} |
298 |
} |
299 |
|
300 |
|
301 |
} |
302 |
else if ([encodedMessage length]) { |
303 |
__block OTROutgoingMessage *outgoingMessage = nil; |
304 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
305 |
outgoingMessage = [[OTROutgoingMessage alloc] init]; |
306 |
outgoingMessage.text = encodedMessage; |
307 |
OTRBuddy *buddy = [self buddyForUsername:username accountName:accountName transaction:transaction]; |
308 |
outgoingMessage.buddyUniqueId = buddy.uniqueId; |
309 |
|
310 |
} completionBlock:^{ |
311 |
[[OTRProtocolManager sharedInstance] sendMessage:outgoingMessage]; |
312 |
}]; |
313 |
} |
314 |
} |
315 |
|
316 |
- (void)otrKit:(OTRKit *)otrKit decodedMessage:(NSString *)decodedMessage tlvs:(NSArray<OTRTLV *> *)tlvs wasEncrypted:(BOOL)wasEncrypted username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol fingerprint:(OTRFingerprint *)fingerprint tag:(id)tag error:(NSError *)error |
317 |
{ |
318 |
//decodedMessage can be nil if just TLV |
319 |
OTRIncomingMessage *originalMessage = nil; |
320 |
if ([tag isKindOfClass:[OTRIncomingMessage class]]) { |
321 |
originalMessage = [tag copy]; |
322 |
} |
323 |
NSParameterAssert(originalMessage); |
324 |
|
325 |
decodedMessage = [OTRUtilities stripHTML:decodedMessage]; |
326 |
decodedMessage = [decodedMessage stringByTrimmingCharactersInSet: |
327 |
[NSCharacterSet whitespaceCharacterSet]]; |
328 |
|
329 |
if ([decodedMessage length]) { |
330 |
originalMessage.text = decodedMessage; |
331 |
|
332 |
if (wasEncrypted) { |
333 |
originalMessage.messageSecurityInfo = [[OTRMessageEncryptionInfo alloc] initWithOTRFingerprint:fingerprint.fingerprint]; |
334 |
} |
335 |
__block OTRXMPPManager *xmpp = nil; |
336 |
__block OTRAccount *account = nil; |
337 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
338 |
[originalMessage saveWithTransaction:transaction]; |
339 |
//Update lastMessageDate for sorting and grouping |
340 |
OTRBuddy *buddy = [OTRBuddy fetchObjectWithUniqueID:originalMessage.buddyUniqueId transaction:transaction]; |
341 |
buddy.lastMessageId = originalMessage.uniqueId; |
342 |
[buddy saveWithTransaction:transaction]; |
343 |
|
344 |
// Send delivery receipt |
345 |
account = [OTRAccount fetchObjectWithUniqueID:buddy.accountUniqueId transaction:transaction]; |
346 |
xmpp = (OTRXMPPManager*) [[OTRProtocolManager sharedInstance] protocolForAccount:account]; |
347 |
[xmpp sendDeliveryReceiptForMessage:originalMessage]; |
348 |
|
349 |
[xmpp.fileTransferManager createAndDownloadItemsIfNeededWithMessage:originalMessage force:NO transaction:transaction]; |
350 |
[[UIApplication sharedApplication] showLocalNotification:originalMessage transaction:transaction]; |
351 |
}]; |
352 |
} |
353 |
|
354 |
if ([tlvs count]) { |
355 |
DDLogVerbose(@"Found TLVS: %@",tlvs); |
356 |
} |
357 |
} |
358 |
|
359 |
- (void)otrKit:(OTRKit *)otrKit updateMessageState:(OTRKitMessageState)messageState username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol fingerprint:(OTRFingerprint *)fingerprint |
360 |
{ |
361 |
__block OTRBuddy *buddy = nil; |
362 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { |
363 |
buddy = [self buddyForUsername:username accountName:accountName transaction:transaction]; |
364 |
} completionBlock:^{ |
365 |
if(!buddy) { |
366 |
// We couldn't find the budy. This is very strange and shouldn't happen. |
367 |
return; |
368 |
} |
369 |
|
370 |
[[NSNotificationCenter defaultCenter] postNotificationName:OTRMessageStateDidChangeNotification object:buddy userInfo:@{OTRMessageStateKey:@([[self class] convertEncryptionState:messageState])}]; |
371 |
}]; |
372 |
} |
373 |
|
374 |
- (BOOL) otrKit:(OTRKit*)otrKit |
375 |
isUsernameLoggedIn:(NSString*)username |
376 |
accountName:(NSString*)accountName |
377 |
protocol:(NSString*)protocol { |
378 |
|
379 |
__block OTRBuddy *buddy = nil; |
380 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { |
381 |
buddy = [self buddyForUsername:username accountName:accountName transaction:transaction]; |
382 |
}]; |
383 |
|
384 |
if(!buddy || buddy.currentStatus == OTRThreadStatusOffline) { |
385 |
return NO; |
386 |
} |
387 |
else { |
388 |
return YES; |
389 |
} |
390 |
} |
391 |
|
392 |
- (void) otrKit:(OTRKit*)otrKit |
393 |
showFingerprintConfirmationForTheirHash:(NSString*)theirHash |
394 |
ourHash:(NSString*)ourHash |
395 |
username:(NSString*)username |
396 |
accountName:(NSString*)accountName |
397 |
protocol:(NSString*)protocol |
398 |
{ |
399 |
//changed user fingerprint |
400 |
} |
401 |
|
402 |
- (void) otrKit:(OTRKit*)otrKit |
403 |
handleSMPEvent:(OTRKitSMPEvent)event |
404 |
progress:(double)progress |
405 |
question:(NSString*)question |
406 |
username:(NSString*)username |
407 |
accountName:(NSString*)accountName |
408 |
protocol:(NSString*)protocol |
409 |
{ |
410 |
|
411 |
} |
412 |
|
413 |
- (void) otrKit:(OTRKit *)otrKit handleMessageEvent:(OTRKitMessageEvent)event message:(NSString *)message username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol tag:(id)tag error:(NSError *)error { |
414 |
//incoming and outgoing errors and other events |
415 |
DDLogWarn(@"Message Event: %d Error:%@",(int)event,[OTREncryptionManager errorForMessageEvent:event string:nil].localizedDescription); |
416 |
|
417 |
if ([tag isKindOfClass:[OTRBaseMessage class]]) { |
418 |
__block NSError *error = nil; |
419 |
|
420 |
// These are the errors caught and |
421 |
switch (event) { |
422 |
case OTRKitMessageEventEncryptionError: |
423 |
case OTRKitMessageEventReceivedMessageNotInPrivate: |
424 |
case OTRKitMessageEventReceivedMessageUnreadable: |
425 |
case OTRKitMessageEventReceivedMessageMalformed: |
426 |
case OTRKitMessageEventReceivedMessageGeneralError: |
427 |
case OTRKitMessageEventReceivedMessageUnrecognized: |
428 |
error = [OTREncryptionManager errorForMessageEvent:event string:message]; |
429 |
break; |
430 |
default: |
431 |
break; |
432 |
} |
433 |
if (error != nil) { |
434 |
if ([tag isKindOfClass:[OTRBaseMessage class]]) { |
435 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
436 |
OTRBaseMessage *dbMessage = [[OTRBaseMessage fetchObjectWithUniqueID:((OTRBaseMessage *)tag).uniqueId transaction:transaction] copy]; |
437 |
dbMessage.error = error; |
438 |
dbMessage.text = [OTREncryptionManager errorForMessageEvent:event string:nil].localizedDescription; |
439 |
[dbMessage saveWithTransaction:transaction]; |
440 |
//Remove the action if there is an error on the parent message. |
441 |
NSString * actionKey = [OTRYapMessageSendAction actionKeyForMessageKey:dbMessage.uniqueId messageCollection:[OTRBaseMessage collection]]; |
442 |
[transaction removeObjectForKey:actionKey inCollection:[OTRYapMessageSendAction collection]]; |
443 |
}]; |
444 |
} |
445 |
|
446 |
// Inject message to recipient indicating error |
447 |
NSString *errorString = [NSString stringWithFormat:@"OTR Error: %@", [OTREncryptionManager errorForMessageEvent:event string:nil].localizedDescription]; |
448 |
[self otrKit:self.otrKit injectMessage:errorString username:username accountName:accountName protocol:protocol fingerprint:nil tag:tag]; |
449 |
// automatically renegotiate a new session when there's an error |
450 |
[self.otrKit initiateEncryptionWithUsername:username accountName:accountName protocol:protocol]; |
451 |
} |
452 |
} |
453 |
} |
454 |
|
455 |
- (void) otrKit:(OTRKit*)otrKit |
456 |
receivedSymmetricKey:(NSData*)symmetricKey |
457 |
forUse:(NSUInteger)use |
458 |
useData:(NSData*)useData |
459 |
username:(NSString*)username |
460 |
accountName:(NSString*)accountName |
461 |
protocol:(NSString*)protocol |
462 |
{ |
463 |
DDLogVerbose(@"Received Symetric Key"); |
464 |
} |
465 |
|
466 |
////// Optional ////// |
467 |
|
468 |
- (void)otrKit:(OTRKit *)otrKit willStartGeneratingPrivateKeyForAccountName:(NSString *)accountName protocol:(NSString *)protocol |
469 |
{ |
470 |
__block OTRAccount *account = nil; |
471 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { |
472 |
|
473 |
account = [[OTRAccount allAccountsWithUsername:accountName transaction:transaction] firstObject]; |
474 |
} completionBlock:^{ |
475 |
[[NSNotificationCenter defaultCenter] postNotificationName:OTRWillStartGeneratingPrivateKeyNotification object:account]; |
476 |
}]; |
477 |
|
478 |
|
479 |
} |
480 |
|
481 |
- (void)otrKit:(OTRKit *)otrKit didFinishGeneratingPrivateKeyForAccountName:(NSString *)accountName protocol:(NSString *)protocol error:(NSError *)error |
482 |
{ |
483 |
__block OTRAccount *account = nil; |
484 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) { |
485 |
account = [[OTRAccount allAccountsWithUsername:accountName transaction:transaction] firstObject];; |
486 |
} completionBlock:^{ |
487 |
[[NSNotificationCenter defaultCenter] postNotificationName:OTRDidFinishGeneratingPrivateKeyNotification object:account]; |
488 |
}]; |
489 |
} |
490 |
|
491 |
#pragma - mark Class Methods |
492 |
|
493 |
+ (NSError *)errorForMessageEvent:(OTRKitMessageEvent)event string:(NSString*)string |
494 |
{ |
495 |
|
496 |
NSString *eventString = [OTREncryptionManager stringForEvent:event]; |
497 |
|
498 |
NSInteger code = 200 + event; |
499 |
NSMutableString *description = [NSMutableString stringWithString:ENCRYPTION_ERROR_STRING()]; |
500 |
if (string.length) { |
501 |
[description appendFormat:@"\n\n%@: %@", string, eventString]; |
502 |
} |
503 |
NSMutableDictionary *userInfo = [@{NSLocalizedDescriptionKey:description} mutableCopy]; |
504 |
if ([eventString length]) { |
505 |
[userInfo setObject:eventString forKey:NSLocalizedFailureReasonErrorKey]; |
506 |
} |
507 |
NSError *error = [NSError errorWithDomain:kOTRErrorDomain code:code userInfo:userInfo]; |
508 |
|
509 |
|
510 |
return error; |
511 |
} |
512 |
|
513 |
+ (NSString *)stringForEvent:(OTRKitMessageEvent)event |
514 |
{ |
515 |
NSString *string = nil; |
516 |
switch (event) { |
517 |
case OTRKitMessageEventEncryptionRequired: |
518 |
string = OTRL_MSGEVENT_ENCRYPTION_REQUIRED_STRING(); |
519 |
break; |
520 |
case OTRKitMessageEventEncryptionError: |
521 |
string = OTRL_MSGEVENT_ENCRYPTION_ERROR_STRING(); |
522 |
break; |
523 |
case OTRKitMessageEventConnectionEnded: |
524 |
string = OTRL_MSGEVENT_CONNECTION_ENDED_STRING(); |
525 |
break; |
526 |
case OTRKitMessageEventSetupError: |
527 |
string = OTRL_MSGEVENT_SETUP_ERROR_STRING(); |
528 |
break; |
529 |
case OTRKitMessageEventMessageReflected: |
530 |
string = OTRL_MSGEVENT_MSG_REFLECTED_STRING(); |
531 |
break; |
532 |
case OTRKitMessageEventMessageResent: |
533 |
string = OTRL_MSGEVENT_MSG_RESENT_STRING(); |
534 |
break; |
535 |
case OTRKitMessageEventReceivedMessageNotInPrivate: |
536 |
string = OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE_STRING(); |
537 |
break; |
538 |
case OTRKitMessageEventReceivedMessageUnreadable: |
539 |
string = OTRL_MSGEVENT_RCVDMSG_UNREADABLE_STRING(); |
540 |
break; |
541 |
case OTRKitMessageEventReceivedMessageMalformed: |
542 |
string = OTRL_MSGEVENT_RCVDMSG_MALFORMED_STRING(); |
543 |
break; |
544 |
case OTRKitMessageEventLogHeartbeatReceived: |
545 |
string = OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD_STRING(); |
546 |
break; |
547 |
case OTRKitMessageEventLogHeartbeatSent: |
548 |
string = OTRL_MSGEVENT_LOG_HEARTBEAT_SENT_STRING(); |
549 |
break; |
550 |
case OTRKitMessageEventReceivedMessageGeneralError: |
551 |
string = OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR_STRING(); |
552 |
break; |
553 |
case OTRKitMessageEventReceivedMessageUnencrypted: |
554 |
string = OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED_STRING(); |
555 |
break; |
556 |
case OTRKitMessageEventReceivedMessageUnrecognized: |
557 |
string = OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED_STRING(); |
558 |
break; |
559 |
case OTRKitMessageEventReceivedMessageForOtherInstance: |
560 |
string = OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE_STRING(); |
561 |
break; |
562 |
default: |
563 |
break; |
564 |
} |
565 |
return string; |
566 |
} |
567 |
|
568 |
+ (OTREncryptionMessageState)convertEncryptionState:(NSUInteger)messageState |
569 |
{ |
570 |
switch (messageState) { |
571 |
case OTRKitMessageStateEncrypted: |
572 |
return OTREncryptionMessageStateEncrypted; |
573 |
case OTRKitMessageStatePlaintext: |
574 |
return OTREncryptionMessageStatePlaintext; |
575 |
case OTRKitMessageStateFinished: |
576 |
return OTREncryptionMessageStateFinished; |
577 |
} |
578 |
return OTREncryptionMessageStateError; |
579 |
} |
580 |
|
581 |
+ (BOOL) setFileProtection:(NSString*)fileProtection path:(NSString*)path { |
582 |
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:fileProtection forKey:NSFileProtectionKey]; |
583 |
NSError * error = nil; |
584 |
BOOL success = [[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:path error:&error]; |
585 |
if (!success) |
586 |
{ |
587 |
DDLogError(@"error encrypting store: %@", error.userInfo); |
588 |
} |
589 |
return success; |
590 |
} |
591 |
|
592 |
+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL |
593 |
{ |
594 |
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); |
595 |
|
596 |
NSError *error = nil; |
597 |
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES] |
598 |
forKey: NSURLIsExcludedFromBackupKey error: &error]; |
599 |
if(!success){ |
600 |
DDLogError(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); |
601 |
} |
602 |
return success; |
603 |
} |
604 |
|
605 |
#pragma mark OTRDataHandlerDelegate methods |
606 |
|
607 |
- (void)dataHandler:(OTRDataHandler *)dataHandler transfer:(OTRDataTransfer *)transfer fingerprint:(OTRFingerprint *)fingerprint error:(NSError *)error |
608 |
{ |
609 |
DDLogError(@"error with file transfer: %@ %@", transfer, error); |
610 |
} |
611 |
|
612 |
- (void)dataHandler:(OTRDataHandler *)dataHandler offeredTransfer:(OTRDataIncomingTransfer *)transfer fingerprint:(OTRFingerprint *)fingerprint |
613 |
{ |
614 |
DDLogInfo(@"offered file transfer: %@", transfer); |
615 |
|
616 |
// for now, just accept all incoming files |
617 |
[dataHandler startIncomingTransfer:transfer]; |
618 |
//Create placeholder for updating progress |
619 |
|
620 |
OTRIncomingMessage *newMessage = [((OTRIncomingMessage *)transfer.tag) copy]; |
621 |
newMessage.messageSecurityInfo = [[OTRMessageEncryptionInfo alloc] initWithOTRFingerprint:fingerprint.fingerprint]; |
622 |
newMessage.text = nil; |
623 |
|
624 |
OTRMediaItem *mediaItem = [OTRMediaItem incomingItemWithFilename:transfer.fileName mimeType:transfer.mimeType]; |
625 |
|
626 |
newMessage.mediaItemUniqueId = mediaItem.uniqueId; |
627 |
|
628 |
|
629 |
//Todo This needs to be moved |
630 |
// if ([[OTRAppDelegate appDelegate].messagesViewController otr_isVisible] && [[OTRAppDelegate appDelegate].messagesViewController.buddy.uniqueId isEqualToString:newMessage.buddyUniqueId]) |
631 |
// { |
632 |
// newMessage.read = YES; |
633 |
// } |
634 |
|
635 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
636 |
OTRBuddy *buddy = [OTRBuddy fetchObjectWithUniqueID:newMessage.buddyUniqueId transaction:transaction]; |
637 |
buddy.lastMessageId = newMessage.uniqueId; |
638 |
[newMessage saveWithTransaction:transaction]; |
639 |
[buddy saveWithTransaction:transaction]; |
640 |
[mediaItem saveWithTransaction:transaction]; |
641 |
}]; |
642 |
|
643 |
|
644 |
} |
645 |
|
646 |
- (void)dataHandler:(OTRDataHandler *)dataHandler transfer:(OTRDataTransfer *)transfer progress:(float)progress fingerprint:(OTRFingerprint *)fingerprint |
647 |
{ |
648 |
DDLogInfo(@"[OTRDATA]file transfer %@ progress: %f", transfer.transferId, progress); |
649 |
|
650 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
651 |
OTRBaseMessage *tagMessage = transfer.tag; |
652 |
OTRBaseMessage *databaseMessage = [OTRBaseMessage fetchObjectWithUniqueID:tagMessage.uniqueId transaction:transaction]; |
653 |
OTRMediaItem *mediaItem = [OTRMediaItem fetchObjectWithUniqueID:databaseMessage.mediaItemUniqueId transaction:transaction]; |
654 |
mediaItem.transferProgress = progress; |
655 |
[mediaItem saveWithTransaction:transaction]; |
656 |
[mediaItem touchParentMessageWithTransaction:transaction]; |
657 |
}]; |
658 |
|
659 |
} |
660 |
|
661 |
- (void)dataHandler:(OTRDataHandler *)dataHandler transferComplete:(OTRDataTransfer *)transfer fingerprint:(OTRFingerprint *)fingerprint |
662 |
{ |
663 |
DDLogInfo(@"transfer complete: %@", transfer); |
664 |
if ([transfer isKindOfClass:[OTRDataOutgoingTransfer class]]) { |
665 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
666 |
OTROutgoingMessage *tagMessage = transfer.tag; |
667 |
OTROutgoingMessage *message = [OTROutgoingMessage fetchObjectWithUniqueID:tagMessage.uniqueId transaction:transaction]; |
668 |
message.delivered = YES; |
669 |
if (message.dateSent == nil) { |
670 |
message.dateSent = [NSDate date]; |
671 |
} |
672 |
message.dateDelivered = [NSDate date]; |
673 |
|
674 |
OTRBuddy *buddy = [OTRBuddy fetchObjectWithUniqueID:message.uniqueId transaction:transaction]; |
675 |
buddy.lastMessageId = message.uniqueId; |
676 |
[message saveWithTransaction:transaction]; |
677 |
[buddy saveWithTransaction:transaction]; |
678 |
}]; |
679 |
} |
680 |
else if ([transfer isKindOfClass:[OTRDataIncomingTransfer class]]) { |
681 |
|
682 |
__block OTRIncomingMessage *tagMessage = transfer.tag; |
683 |
|
684 |
__block OTRIncomingMessage *message = nil; |
685 |
__block OTRMediaItem *mediaItem = nil; |
686 |
__block OTRBuddy *buddy = nil; |
687 |
|
688 |
[[OTRDatabaseManager sharedInstance].readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { |
689 |
message = [OTRIncomingMessage fetchObjectWithUniqueID:tagMessage.uniqueId transaction:transaction]; |
690 |
mediaItem = [OTRMediaItem fetchObjectWithUniqueID:message.mediaItemUniqueId transaction:transaction]; |
691 |
buddy = [OTRBuddy fetchObjectWithUniqueID:message.uniqueId transaction:transaction]; |
692 |
}]; |
693 |
|
694 |
mediaItem.transferProgress = 1; |
695 |
|
696 |
if ([mediaItem isKindOfClass:[OTRAudioItem class]]) { |
697 |
OTRAudioItem *audioItem = (OTRAudioItem *)mediaItem; |
698 |
|
699 |
[[OTRMediaFileManager sharedInstance] setData:transfer.fileData forItem:audioItem buddyUniqueId:message.buddyUniqueId completion:^(NSInteger bytesWritten, NSError *error) { |
700 |
|
701 |
NSURL *url = [[OTRMediaServer sharedInstance] urlForMediaItem:audioItem buddyUniqueId:message.buddyUniqueId]; |
702 |
[audioItem populateFromDataAtUrl:url]; |
703 |
|
704 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
705 |
[audioItem saveWithTransaction:transaction]; |
706 |
[message saveWithTransaction:transaction]; |
707 |
buddy.lastMessageId = message.uniqueId; |
708 |
[buddy saveWithTransaction:transaction]; |
709 |
}]; |
710 |
|
711 |
|
712 |
} completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; |
713 |
|
714 |
} else if ([mediaItem isKindOfClass:[OTRImageItem class]]) { |
715 |
OTRImageItem *imageItem = (OTRImageItem *)mediaItem; |
716 |
|
717 |
UIImage *tempImage = [UIImage imageWithData:transfer.fileData]; |
718 |
imageItem.size = tempImage.size; |
719 |
|
720 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
721 |
[message saveWithTransaction:transaction]; |
722 |
[imageItem saveWithTransaction:transaction]; |
723 |
buddy.lastMessageId = message.uniqueId; |
724 |
[buddy saveWithTransaction:transaction]; |
725 |
} completionBlock:^{ |
726 |
[[OTRMediaFileManager sharedInstance] setData:transfer.fileData forItem:imageItem buddyUniqueId:message.buddyUniqueId completion:^(NSInteger bytesWritten, NSError *error) { |
727 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
728 |
[imageItem touchParentMessageWithTransaction:transaction]; |
729 |
}]; |
730 |
} completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; |
731 |
}]; |
732 |
|
733 |
|
734 |
} else if ([mediaItem isKindOfClass:[OTRVideoItem class]]) { |
735 |
OTRVideoItem *videoItem = (OTRVideoItem *)mediaItem; |
736 |
|
737 |
[[OTRMediaFileManager sharedInstance] setData:transfer.fileData forItem:videoItem buddyUniqueId:message.buddyUniqueId completion:^(NSInteger bytesWritten, NSError *error) { |
738 |
|
739 |
|
740 |
[[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { |
741 |
[videoItem saveWithTransaction:transaction]; |
742 |
[message saveWithTransaction:transaction]; |
743 |
buddy.lastMessageId = message.uniqueId; |
744 |
[buddy saveWithTransaction:transaction]; |
745 |
}]; |
746 |
|
747 |
} completionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; |
748 |
} |
749 |
} |
750 |
} |
751 |
|
752 |
|
753 |
@end |