Statistics
| Branch: | Tag: | Revision:

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