Revision 8d76e2e3 ChatSecure/Classes/Controllers/OTROMEMOSignalCoordinator.swift

View differences:

ChatSecure/Classes/Controllers/OTROMEMOSignalCoordinator.swift
27 27
    @objc open weak var omemoModuleQueue:DispatchQueue?
28 28
    @objc open var callbackQueue:DispatchQueue
29 29
    @objc open let workQueue:DispatchQueue
30
    @objc open let messageStorage: MessageStorage
31
    
30 32
    fileprivate var myJID:XMPPJID? {
31 33
        get {
32 34
            return omemoModule?.xmppStream?.myJID
......
40 42
     - parameter accountYapKey: The accounts unique yap key
41 43
     - parameter databaseConnection: A yap database connection on which all operations will be completed on
42 44
 `  */
43
    @objc public required init(accountYapKey:String,  databaseConnection:YapDatabaseConnection) throws {
45
    @objc public required init(accountYapKey:String,  databaseConnection:YapDatabaseConnection,
46
                               messageStorage: MessageStorage) throws {
44 47
        try self.signalEncryptionManager = OTRAccountSignalEncryptionManager(accountKey: accountYapKey,databaseConnection: databaseConnection)
45 48
        self.omemoStorageManager = OTROMEMOStorageManager(accountKey: accountYapKey, accountCollection: OTRAccount.collection, databaseConnection: databaseConnection)
46 49
        self.accountYapKey = accountYapKey
......
48 51
        self.outstandingXMPPStanzaResponseBlocks = [:]
49 52
        self.callbackQueue = DispatchQueue(label: "OTROMEMOSignalCoordinator-callback", attributes: [])
50 53
        self.workQueue = DispatchQueue(label: "OTROMEMOSignalCoordinator-work", attributes: [])
54
        self.messageStorage = messageStorage
51 55
    }
52 56
    
53 57
    /**
......
355 359
        }
356 360
    }
357 361
    
358
    open func processKeyData(_ keyData: [OMEMOKeyData], iv: Data, senderDeviceId: UInt32, fromJID: XMPPJID, payload: Data?, message: XMPPMessage) {
362
    open func processKeyData(_ keyData: [OMEMOKeyData], iv: Data, senderDeviceId: UInt32, forJID: XMPPJID, payload: Data?, delayed: Date?, forwarded: Bool, isIncoming: Bool, message: XMPPMessage) {
359 363
        let aesGcmBlockLength = 16
360
        guard let encryptedPayload = payload, encryptedPayload.count > 0 else {
364
        guard let encryptedPayload = payload, encryptedPayload.count > 0, let myJID = self.myJID else {
361 365
            return
362 366
        }
363
        
367
        var addressJID = forJID.bareJID
368
        if !isIncoming {
369
            addressJID = myJID.bareJID
370
        }
364 371
        let rid = self.signalEncryptionManager.registrationId
365 372
        
366 373
        //Could have multiple matching device id. This is extremely rare but possible that the sender has another device that collides with our device id.
367 374
        var unencryptedKeyData: Data?
368
        for key in keyData {
369
            if key.deviceId == rid {
370
                let keyData = key.data
371
                do {
372
                    unencryptedKeyData = try self.signalEncryptionManager.decryptFromAddress(keyData, name: fromJID.bare, deviceId: senderDeviceId)
373
                    // have successfully decripted the AES key. We should break and use it to decrypt the payload
374
                    break
375
                } catch let error {
376
                    DDLogError("Error decrypting: \(error)")
377
                    let nsError = error as NSError
378
                    if nsError.domain == SignalErrorDomain, nsError.code == SignalError.duplicateMessage.rawValue {
379
                        // duplicate messages are benign and can be ignored
380
                        return
381
                    }
382
                    let buddyAddress = SignalAddress(name: fromJID.bare, deviceId: Int32(senderDeviceId))
383
                    if self.signalEncryptionManager.storage.sessionRecordExists(for: buddyAddress) {
384
                        // Session is corrupted
385
                        let _ = self.signalEncryptionManager.storage.deleteSessionRecord(for: buddyAddress)
386
                        DDLogError("Session exists and is possibly corrupted. Deleting...")
387
                    }
375
        for key in keyData where key.deviceId == rid {
376
            let keyData = key.data
377
            do {
378
                unencryptedKeyData = try self.signalEncryptionManager.decryptFromAddress(keyData, name: addressJID.bare, deviceId: senderDeviceId)
379
                // have successfully decripted the AES key. We should break and use it to decrypt the payload
380
                break
381
            } catch let error {
382
                DDLogError("Error decrypting OMEMO message for \(addressJID): \(error) \(message)")
383
                let nsError = error as NSError
384
                if nsError.domain == SignalErrorDomain, nsError.code == SignalError.duplicateMessage.rawValue {
385
                    // duplicate messages are benign and can be ignored
386
                    DDLogInfo("Ignoring duplicate OMEMO message: \(message)")
388 387
                    return
389 388
                }
389
                let buddyAddress = SignalAddress(name: addressJID.bare, deviceId: Int32(senderDeviceId))
390
                if self.signalEncryptionManager.storage.sessionRecordExists(for: buddyAddress) {
391
                    // Session is corrupted
392
                    let _ = self.signalEncryptionManager.storage.deleteSessionRecord(for: buddyAddress)
393
                    DDLogError("Session exists and is possibly corrupted. Deleting...")
394
                }
395
                return
390 396
            }
391 397
        }
392 398
        
......
418 424
        }
419 425
        
420 426
        do {
421
            guard let messageBody = try OTRSignalEncryptionHelper.decryptData(encryptedBody, key: aesKey, iv: iv, authTag: tag) else {
422
                return
423
            }
424
            let messageString = String(data: messageBody, encoding: String.Encoding.utf8)
425
            var databaseMessage:OTRBaseMessage = OTRIncomingMessage()
426
            guard let ourJID = self.myJID else {
427
            guard let messageBody = try OTRSignalEncryptionHelper.decryptData(encryptedBody, key: aesKey, iv: iv, authTag: tag),
428
            let messageString = String(data: messageBody, encoding: String.Encoding.utf8),
429
            messageString.count > 0 else {
427 430
                return
428 431
            }
429
            var relatedBuddyUsername: String? = fromJID.bare
430
            var innerMessage = message
431
            if message.isTrustedMessageCarbon(forMyJID: ourJID),
432
                let forwarded = message.messageCarbonForwarded {
433
                //This came from another of our devices this is really going to be an outgoing message
434
                innerMessage = forwarded
435
                if (message.isReceivedMessageCarbon) {
436
                    relatedBuddyUsername = innerMessage.from?.bare
437
                } else {
438
                    relatedBuddyUsername = innerMessage.to?.bare
439
                    let outgoingMessage = OTROutgoingMessage()!
440
                    outgoingMessage.dateSent = Date()
441
                    databaseMessage = outgoingMessage
442
                }
443
            }
444
            
445
            var xmpp: OTRXMPPManager? = nil
446
            var account: OTRAccount? = nil
447 432
            
448
            self.databaseConnection.asyncReadWrite({ (transaction) in
449
                
450
                guard let buddyUsernmae = relatedBuddyUsername, let jid = XMPPJID(string: buddyUsernmae), let buddy = OTRXMPPBuddy.fetchBuddy(jid: jid, accountUniqueId: self.accountYapKey, transaction: transaction) else {
433
            let preSave: MessageStorage.PreSave = { message, transaction in
434
                guard let buddy = OTRXMPPBuddy.fetchBuddy(jid: forJID, accountUniqueId: self.accountYapKey, transaction: transaction) else {
451 435
                    return
452 436
                }
453
                databaseMessage.text = messageString
454
                databaseMessage.buddyUniqueId = buddy.uniqueId
455
                
437

  
456 438
                let deviceNumber = NSNumber(value: senderDeviceId as UInt32)
457 439
                let deviceYapKey = OTROMEMODevice.yapKey(withDeviceId: deviceNumber, parentKey: buddy.uniqueId, parentCollection: OTRBuddy.collection)
458
                databaseMessage.messageSecurityInfo = OTRMessageEncryptionInfo.init(omemoDevice: deviceYapKey, collection: OTROMEMODevice.collection)
459
                if let id = innerMessage.elementID {
460
                    databaseMessage.messageId = id
461
                }
440
                message.messageSecurityInfo = OTRMessageEncryptionInfo.init(omemoDevice: deviceYapKey, collection: OTROMEMODevice.collection)
462 441
                
463
                databaseMessage.save(with: transaction)
442
                message.save(with: transaction)
464 443
                
465 444
                // Should we be using the date of the xmpp message?
466
                buddy.lastMessageId = databaseMessage.uniqueId
445
                buddy.lastMessageId = message.uniqueId
467 446
                buddy.save(with: transaction)
468 447
                
469 448
                //Update device last received message
......
472 451
                }
473 452
                let newDevice = OTROMEMODevice(deviceId: device.deviceId, trustLevel: device.trustLevel, parentKey: device.parentKey, parentCollection: device.parentCollection, publicIdentityKeyData: device.publicIdentityKeyData, lastSeenDate: Date())
474 453
                newDevice.save(with: transaction)
475
                
476
                // Send delivery receipt
477
                account = OTRAccount.fetchObject(withUniqueID: buddy.accountUniqueId, transaction: transaction)
478
                if let account = account {
479
                    xmpp = OTRProtocolManager.sharedInstance().protocol(for: account) as? OTRXMPPManager
480
                } else {
481
                    return
482
                }
483
                
484
                if let incomingMessage = databaseMessage as? OTRIncomingMessage {
485
                    xmpp?.sendDeliveryReceipt(for: incomingMessage)
486
                }
487
                
488
                }, completionQueue: DispatchQueue.main,
489
                   completionBlock: {
490
                    guard let _ = databaseMessage.text else {
491
                        return
492
                    }
493
                    
494
                    xmpp?.fileTransferManager.createAndDownloadItemsIfNeeded(message: databaseMessage, readConnection: OTRDatabaseManager.shared.readOnlyDatabaseConnection ?? self.databaseConnection, force: false)
495
                    UIApplication.shared.showLocalNotification(databaseMessage)
496
            })
497
            // Display local notification
454
            }
498 455
            
499
        } catch {
456
            if forwarded {
457
                self.messageStorage.handleForwardedMessage(message, forJID: forJID, body: messageString, accountId: self.accountYapKey, delayed: delayed, isIncoming: isIncoming, preSave: preSave)
458
            } else {
459
                self.messageStorage.handleDirectMessage(message, body: messageString, accountId: self.accountYapKey, preSave: preSave)
460
            }
461
        } catch let error {
462
            DDLogError("Message decryption error: \(error)")
500 463
            return
501 464
        }
502

  
503 465
    }
504 466
}
505 467

  
......
595 557
    }
596 558
    
597 559
    public func omemo(_ omemo: OMEMOModule, receivedKeyData keyData: [OMEMOKeyData], iv: Data, senderDeviceId: UInt32, from fromJID: XMPPJID, payload: Data?, message: XMPPMessage) {
598
        self.processKeyData(keyData, iv: iv, senderDeviceId: senderDeviceId, fromJID: fromJID, payload: payload, message: message)
560
        self.processKeyData(keyData, iv: iv, senderDeviceId: senderDeviceId, forJID: fromJID, payload: payload, delayed: nil, forwarded: false, isIncoming: true, message: message)
561
    }
562
    
563
    public func omemo(_ omemo: OMEMOModule, receivedForwardedKeyData keyData: [OMEMOKeyData], iv: Data, senderDeviceId: UInt32, for forJID: XMPPJID, payload: Data?, isIncoming: Bool, delayed: Date?, forwardedMessage: XMPPMessage, originalMessage: XMPPMessage) {
564
        self.processKeyData(keyData, iv: iv, senderDeviceId: senderDeviceId, forJID: forJID, payload: payload, delayed: delayed, forwarded: true, isIncoming: isIncoming, message: forwardedMessage)
599 565
    }
600 566
}
601 567

  

Also available in: Unified diff