Revision 8d76e2e3 ChatSecure/Classes/Controllers/OTROMEMOSignalCoordinator.swift
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