2017-01-24 21:47:41 +01:00
//
2019-01-04 15:19:41 +01:00
// Copyright ( c ) 2019 Open Whisper Systems . All rights reserved .
2017-01-24 21:47:41 +01:00
//
2015-12-07 03:31:43 +01:00
2017-09-14 17:00:30 +02:00
# import "OWSMessageManager.h"
2017-11-29 21:27:19 +01:00
# import "AppContext.h"
2018-01-26 22:11:05 +01:00
# import "AppReadiness.h"
2016-08-26 01:01:35 +02:00
# import "ContactsManagerProtocol.h"
# import "MimeTypeUtil.h"
2018-10-16 19:30:25 +02:00
# import "NSNotificationCenter+OWS.h"
2018-12-19 22:35:43 +01:00
# import "NSString+SSK.h"
2016-12-18 22:08:26 +01:00
# import "NotificationsProtocol.h"
2018-11-07 23:49:25 +01:00
# import "OWSAttachmentDownloads.h"
2017-04-03 20:42:04 +02:00
# import "OWSBlockingManager.h"
2016-12-18 22:08:26 +01:00
# import "OWSCallMessageHandler.h"
2018-05-01 14:52:59 +02:00
# import "OWSContact.h"
2017-11-16 15:54:55 +01:00
# import "OWSDevice.h"
2018-10-22 18:31:28 +02:00
# import "OWSDevicesService.h"
2016-10-05 17:42:44 +02:00
# import "OWSDisappearingConfigurationUpdateInfoMessage.h"
# import "OWSDisappearingMessagesConfiguration.h"
# import "OWSDisappearingMessagesJob.h"
2019-05-21 03:40:29 +02:00
# import "LKEphemeralMessage.h"
2020-01-17 00:38:16 +01:00
# import "LKSessionRequestMessage.h"
2019-09-24 08:03:31 +02:00
# import "LKDeviceLinkMessage.h"
2017-09-14 17:00:30 +02:00
# import "OWSIdentityManager.h"
2017-02-16 00:32:27 +01:00
# import "OWSIncomingMessageFinder.h"
2016-08-23 22:38:05 +02:00
# import "OWSIncomingSentMessageTranscript.h"
2016-10-14 23:00:29 +02:00
# import "OWSMessageSender.h"
2018-01-30 21:05:04 +01:00
# import "OWSMessageUtils.h"
2018-10-11 21:29:01 +02:00
# import "OWSOutgoingReceiptManager.h"
2018-03-05 15:30:58 +01:00
# import "OWSPrimaryStorage+SessionStore.h"
2019-05-13 04:19:05 +02:00
# import "OWSPrimaryStorage+Loki.h"
2018-03-05 15:30:58 +01:00
# import "OWSPrimaryStorage.h"
2017-09-15 21:28:44 +02:00
# import "OWSReadReceiptManager.h"
2016-10-05 17:42:44 +02:00
# import "OWSRecordTranscriptJob.h"
2016-08-27 00:07:54 +02:00
# import "OWSSyncGroupsMessage.h"
2017-05-05 23:22:56 +02:00
# import "OWSSyncGroupsRequestMessage.h"
2017-08-02 19:12:26 +02:00
# import "ProfileManagerProtocol.h"
2018-08-31 19:12:40 +02:00
# import "SSKEnvironment.h"
2016-04-08 09:38:34 +02:00
# import "TSAccountManager.h"
2018-04-05 18:01:53 +02:00
# import "TSAttachment.h"
# import "TSAttachmentPointer.h"
2018-04-07 02:08:17 +02:00
# import "TSAttachmentStream.h"
2016-07-28 01:58:49 +02:00
# import "TSContactThread.h"
2015-12-07 03:31:43 +01:00
# import "TSDatabaseView.h"
2016-07-28 01:58:49 +02:00
# import "TSGroupModel.h"
# import "TSGroupThread.h"
2017-09-14 17:00:30 +02:00
# import "TSIncomingMessage.h"
2015-12-07 03:31:43 +01:00
# import "TSInfoMessage.h"
2016-09-23 22:55:56 +02:00
# import "TSNetworkManager.h"
2017-09-14 17:00:30 +02:00
# import "TSOutgoingMessage.h"
2018-02-07 18:44:09 +01:00
# import "TSQuotedMessage.h"
2018-09-25 19:09:55 +02:00
# import < SignalCoreKit / Cryptography . h >
2018-09-21 21:41:10 +02:00
# import < SignalCoreKit / NSDate + OWS . h >
2020-02-17 01:24:16 +01:00
# import < SignalMetadataKit / SignalMetadataKit - Swift . h >
2019-05-21 03:40:29 +02:00
# import < SignalServiceKit / NSObject + Casting . h >
2018-10-22 18:31:28 +02:00
# import < SignalServiceKit / SignalRecipient . h >
2018-06-07 07:57:59 +02:00
# import < SignalServiceKit / SignalServiceKit - Swift . h >
2017-12-19 03:42:50 +01:00
# import < YapDatabase / YapDatabase . h >
2019-11-12 03:04:13 +01:00
# import "OWSDispatch.h"
2020-02-14 06:32:47 +01:00
# import "OWSBatchMessageProcessor.h"
# import "OWSQueues.h"
2015-12-07 03:31:43 +01:00
2016-10-05 17:42:44 +02:00
NS_ASSUME _NONNULL _BEGIN
2017-09-14 17:00:30 +02:00
@ interface OWSMessageManager ( )
2016-10-01 20:42:39 +02:00
2018-03-05 15:30:58 +01:00
@ property ( nonatomic , readonly ) OWSPrimaryStorage * primaryStorage ;
2017-09-14 17:00:30 +02:00
@ property ( nonatomic , readonly ) YapDatabaseConnection * dbConnection ;
2018-09-20 18:52:43 +02:00
@ property ( nonatomic , readonly ) OWSIncomingMessageFinder * incomingMessageFinder ;
2016-10-01 20:42:39 +02:00
@ end
2017-05-09 20:38:49 +02:00
# pragma mark -
2017-09-14 17:00:30 +02:00
@ implementation OWSMessageManager
2015-12-07 03:31:43 +01:00
2017-09-14 17:00:30 +02:00
+ ( instancetype ) sharedManager
{
2018-09-20 18:52:43 +02:00
OWSAssertDebug ( SSKEnvironment . shared . messageManager ) ;
2015-12-07 03:31:43 +01:00
2018-09-20 18:52:43 +02:00
return SSKEnvironment . shared . messageManager ;
2016-09-23 22:55:56 +02:00
}
2018-09-20 18:52:43 +02:00
- ( instancetype ) initWithPrimaryStorage : ( OWSPrimaryStorage * ) primaryStorage
2016-09-23 22:55:56 +02:00
{
2015-12-07 03:31:43 +01:00
self = [ super init ] ;
2016-09-23 22:55:56 +02:00
if ( ! self ) {
return self ;
2015-12-07 03:31:43 +01:00
}
2018-03-05 15:30:58 +01:00
_primaryStorage = primaryStorage ;
_dbConnection = primaryStorage . newDatabaseConnection ;
_incomingMessageFinder = [ [ OWSIncomingMessageFinder alloc ] initWithPrimaryStorage : primaryStorage ] ;
2017-04-01 00:36:08 +02:00
OWSSingletonAssert ( ) ;
2015-12-07 03:31:43 +01:00
return self ;
}
2019-05-17 02:11:06 +02:00
- ( void ) dealloc {
2019-05-20 03:20:03 +02:00
[ NSNotificationCenter . defaultCenter removeObserver : self ] ;
2019-05-17 02:11:06 +02:00
}
2018-10-22 18:31:28 +02:00
# pragma mark - Dependencies
2018-09-20 18:52:43 +02:00
- ( id < OWSCallMessageHandler > ) callMessageHandler
{
OWSAssertDebug ( SSKEnvironment . shared . callMessageHandler ) ;
return SSKEnvironment . shared . callMessageHandler ;
}
- ( id < ContactsManagerProtocol > ) contactsManager
{
OWSAssertDebug ( SSKEnvironment . shared . contactsManager ) ;
return SSKEnvironment . shared . contactsManager ;
}
2018-10-20 19:51:48 +02:00
- ( SSKMessageSenderJobQueue * ) messageSenderJobQueue
2018-09-20 18:52:43 +02:00
{
2018-10-20 19:51:48 +02:00
return SSKEnvironment . shared . messageSenderJobQueue ;
2018-09-20 18:52:43 +02:00
}
- ( OWSBlockingManager * ) blockingManager
{
OWSAssertDebug ( SSKEnvironment . shared . blockingManager ) ;
return SSKEnvironment . shared . blockingManager ;
}
- ( OWSIdentityManager * ) identityManager
{
OWSAssertDebug ( SSKEnvironment . shared . identityManager ) ;
return SSKEnvironment . shared . identityManager ;
}
- ( TSNetworkManager * ) networkManager
{
OWSAssertDebug ( SSKEnvironment . shared . networkManager ) ;
return SSKEnvironment . shared . networkManager ;
}
2018-10-12 17:49:50 +02:00
- ( OWSOutgoingReceiptManager * ) outgoingReceiptManager
{
2018-10-11 21:29:01 +02:00
OWSAssertDebug ( SSKEnvironment . shared . outgoingReceiptManager ) ;
2018-10-11 18:51:58 +02:00
2018-10-11 21:29:01 +02:00
return SSKEnvironment . shared . outgoingReceiptManager ;
2018-10-11 18:51:58 +02:00
}
2018-10-18 22:58:02 +02:00
- ( id < OWSSyncManagerProtocol > ) syncManager
{
2018-10-18 21:59:43 +02:00
OWSAssertDebug ( SSKEnvironment . shared . syncManager ) ;
return SSKEnvironment . shared . syncManager ;
}
2018-10-22 18:31:28 +02:00
- ( TSAccountManager * ) tsAccountManager
{
OWSAssertDebug ( SSKEnvironment . shared . tsAccountManager ) ;
return SSKEnvironment . shared . tsAccountManager ;
}
2018-10-30 17:06:20 +01:00
- ( id < ProfileManagerProtocol > ) profileManager
{
return SSKEnvironment . shared . profileManager ;
}
2018-10-31 00:18:17 +01:00
- ( id < OWSTypingIndicators > ) typingIndicators
{
return SSKEnvironment . shared . typingIndicators ;
}
2018-11-07 23:49:25 +01:00
- ( OWSAttachmentDownloads * ) attachmentDownloads
{
return SSKEnvironment . shared . attachmentDownloads ;
}
2018-10-11 18:51:58 +02:00
# pragma mark -
2017-06-30 18:12:37 +02:00
- ( void ) startObserving
{
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( yapDatabaseModified : )
name : YapDatabaseModifiedNotification
2018-03-05 15:30:58 +01:00
object : OWSPrimaryStorage . sharedManager . dbNotificationObject ] ;
2017-11-29 17:37:49 +01:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( yapDatabaseModified : )
name : YapDatabaseModifiedExternallyNotification
2018-01-11 16:04:03 +01:00
object : nil ] ;
2017-06-30 18:12:37 +02:00
}
- ( void ) yapDatabaseModified : ( NSNotification * ) notification
{
2018-02-14 20:09:27 +01:00
if ( AppReadiness . isAppReady ) {
[ OWSMessageUtils . sharedManager updateApplicationBadgeCount ] ;
} else {
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
2018-11-02 18:51:46 +01:00
[ AppReadiness runNowOrWhenAppDidBecomeReady : ^ {
2018-02-14 20:09:27 +01:00
[ OWSMessageUtils . sharedManager updateApplicationBadgeCount ] ;
} ] ;
} ) ;
}
2017-06-30 18:12:37 +02:00
}
2017-09-13 18:14:22 +02:00
# pragma mark - Blocking
2017-04-25 21:42:49 +02:00
2018-09-09 20:35:52 +02:00
- ( BOOL ) isEnvelopeSenderBlocked : ( SSKProtoEnvelope * ) envelope
2016-08-22 22:09:58 +02:00
{
2018-09-06 19:01:24 +02:00
OWSAssertDebug ( envelope ) ;
2017-09-13 18:14:22 +02:00
2018-09-20 18:52:43 +02:00
return [ self . blockingManager isRecipientIdBlocked : envelope . source ] ;
2017-09-13 18:14:22 +02:00
}
2018-09-09 20:35:52 +02:00
- ( BOOL ) isDataMessageBlocked : ( SSKProtoDataMessage * ) dataMessage envelope : ( SSKProtoEnvelope * ) envelope
{
2018-09-15 16:17:08 +02:00
OWSAssertDebug ( dataMessage ) ;
OWSAssertDebug ( envelope ) ;
2018-09-09 20:35:52 +02:00
if ( dataMessage . group ) {
return [ self . blockingManager isGroupIdBlocked : dataMessage . group . id ] ;
} else {
BOOL senderBlocked = [ self isEnvelopeSenderBlocked : envelope ] ;
// If the envelopeSender was blocked , we never should have gotten as far as decrypting the dataMessage .
2018-09-15 16:17:08 +02:00
OWSAssertDebug ( ! senderBlocked ) ;
2018-09-09 20:35:52 +02:00
return senderBlocked ;
}
}
2017-09-13 18:14:22 +02:00
# pragma mark - message handling
2018-10-30 16:21:26 +01:00
- ( void ) throws_processEnvelope : ( SSKProtoEnvelope * ) envelope
plaintextData : ( NSData * _Nullable ) plaintextData
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2018-10-30 16:21:26 +01:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2019-11-15 03:56:35 +01:00
serverID : ( uint64_t ) serverID
2016-08-22 22:09:58 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2018-11-26 16:24:36 +01:00
if ( ! self . tsAccountManager . isRegistered ) {
2018-08-30 16:31:01 +02:00
OWSFailDebug ( @ "Not registered." ) ;
return ;
}
if ( ! CurrentAppContext ( ) . isMainApp ) {
2020-02-15 00:01:21 +01:00
OWSFail ( @ "Not the main app." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-02-10 01:35:10 +01:00
2020-02-15 00:01:21 +01:00
OWSLogInfo ( @ "Handling decrypted envelope: %@." , [ self descriptionForEnvelope : envelope ] ) ;
2015-12-07 03:31:43 +01:00
2020-01-31 07:01:29 +01:00
if ( ! wasReceivedByUD ) {
if ( ! envelope . hasSource || envelope . source . length < 1 ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Incoming envelope with invalid source." ) ;
2020-01-31 07:01:29 +01:00
return ;
}
if ( ! envelope . hasSourceDevice || envelope . sourceDevice < 1 ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Incoming envelope with invalid source device." ) ;
2020-01-31 07:01:29 +01:00
return ;
}
2018-10-05 15:28:53 +02:00
}
2018-02-16 02:45:28 +01:00
2018-09-15 16:17:08 +02:00
OWSAssertDebug ( ! [ self isEnvelopeSenderBlocked : envelope ] ) ;
2015-12-07 03:31:43 +01:00
2020-02-15 00:01:21 +01:00
// Loki : Ignore any friend requests from before restoration
// The envelope type is set during UD decryption .
2020-02-14 06:32:47 +01:00
uint64_t restorationTime = [ NSNumber numberWithDouble : [ OWSPrimaryStorage . sharedManager getRestorationTime ] ] . unsignedLongLongValue ;
if ( envelope . type = = SSKProtoEnvelopeTypeFriendRequest && envelope . timestamp < restorationTime * 1000 ) {
[ LKLogger print : @ "[Loki] Ignoring friend request received before restoration." ] ;
return ;
}
2018-10-22 18:31:28 +02:00
[ self checkForUnknownLinkedDevice : envelope transaction : transaction ] ;
2017-09-13 18:14:22 +02:00
switch ( envelope . type ) {
2019-05-08 05:33:47 +02:00
case SSKProtoEnvelopeTypeFriendRequest :
2018-08-01 16:45:21 +02:00
case SSKProtoEnvelopeTypeCiphertext :
case SSKProtoEnvelopeTypePrekeyBundle :
2018-10-04 17:33:58 +02:00
case SSKProtoEnvelopeTypeUnidentifiedSender :
2018-08-30 16:31:01 +02:00
if ( ! plaintextData ) {
2018-08-27 18:51:32 +02:00
OWSFailDebug ( @ "missing decrypted data for envelope: %@" , [ self descriptionForEnvelope : envelope ] ) ;
2018-08-30 16:31:01 +02:00
return ;
2017-01-24 21:47:41 +01:00
}
2018-12-02 23:30:31 +01:00
[ self throws_handleEnvelope : envelope
plaintextData : plaintextData
wasReceivedByUD : wasReceivedByUD
2019-11-15 03:56:35 +01:00
transaction : transaction
serverID : serverID ] ;
2017-09-13 18:14:22 +02:00
break ;
2018-08-01 16:45:21 +02:00
case SSKProtoEnvelopeTypeReceipt :
2018-09-06 19:01:24 +02:00
OWSAssertDebug ( ! plaintextData ) ;
2017-09-13 21:35:33 +02:00
[ self handleDeliveryReceipt : envelope transaction : transaction ] ;
2017-09-13 18:14:22 +02:00
break ;
2018-04-16 20:48:29 +02:00
// Other messages are just dismissed for now .
2018-08-01 16:45:21 +02:00
case SSKProtoEnvelopeTypeKeyExchange :
2018-08-27 18:00:28 +02:00
OWSLogWarn ( @ "Received Key Exchange Message, not supported" ) ;
2017-09-13 18:14:22 +02:00
break ;
2018-08-01 16:45:21 +02:00
case SSKProtoEnvelopeTypeUnknown :
2018-08-27 18:00:28 +02:00
OWSLogWarn ( @ "Received an unknown message type" ) ;
2017-09-13 18:14:22 +02:00
break ;
default :
2018-08-27 18:00:28 +02:00
OWSLogWarn ( @ "Received unhandled envelope type: %d" , ( int ) envelope . type ) ;
2017-09-13 18:14:22 +02:00
break ;
2016-12-06 03:32:11 +01:00
}
}
2018-08-01 16:45:21 +02:00
- ( void ) handleDeliveryReceipt : ( SSKProtoEnvelope * ) envelope transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2017-09-13 18:14:22 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2017-09-22 23:23:09 +02:00
// Old - style delivery notices don ' t include a "delivery timestamp" .
2017-09-27 20:19:26 +02:00
[ self processDeliveryReceiptsFromRecipientId : envelope . source
sentTimestamps : @ [
@ ( envelope . timestamp ) ,
]
deliveryTimestamp : nil
transaction : transaction ] ;
2017-09-22 22:40:44 +02:00
}
2017-09-27 20:19:26 +02:00
// deliveryTimestamp is an optional parameter , since legacy
// delivery receipts don ' t have a "delivery timestamp" . Those
// messages repurpose the "timestamp" field to indicate when the
// corresponding message was originally sent .
- ( void ) processDeliveryReceiptsFromRecipientId : ( NSString * ) recipientId
sentTimestamps : ( NSArray < NSNumber * > * ) sentTimestamps
deliveryTimestamp : ( NSNumber * _Nullable ) deliveryTimestamp
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2017-09-22 22:40:44 +02:00
{
2018-08-30 16:31:01 +02:00
if ( recipientId . length < 1 ) {
OWSFailDebug ( @ "Empty recipientId." ) ;
return ;
}
if ( sentTimestamps . count < 1 ) {
OWSFailDebug ( @ "Missing sentTimestamps." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-22 22:40:44 +02:00
for ( NSNumber * nsTimestamp in sentTimestamps ) {
uint64_t timestamp = [ nsTimestamp unsignedLongLongValue ] ;
NSArray < TSOutgoingMessage * > * messages
2018-09-20 22:10:35 +02:00
= ( NSArray < TSOutgoingMessage * > * ) [ TSInteraction interactionsWithTimestamp : timestamp
ofClass : [ TSOutgoingMessage class ]
withTransaction : transaction ] ;
2017-09-22 22:40:44 +02:00
if ( messages . count < 1 ) {
2017-09-27 20:19:26 +02:00
// The service sends delivery receipts for "unpersisted" messages
2017-09-22 22:40:44 +02:00
// like group updates , so these errors are expected to a certain extent .
2017-09-27 20:19:26 +02:00
//
// TODO : persist "early" delivery receipts .
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "Missing message for delivery receipt: %llu" , timestamp ) ;
2017-09-22 22:40:44 +02:00
} else {
if ( messages . count > 1 ) {
2018-08-27 18:55:37 +02:00
OWSLogInfo ( @ "More than one message (%lu) for delivery receipt: %llu" ,
2018-07-18 03:08:53 +02:00
( unsigned long ) messages . count ,
2017-11-08 20:04:51 +01:00
timestamp ) ;
2017-09-22 22:40:44 +02:00
}
for ( TSOutgoingMessage * outgoingMessage in messages ) {
2018-04-23 16:30:51 +02:00
[ outgoingMessage updateWithDeliveredRecipient : recipientId
deliveryTimestamp : deliveryTimestamp
transaction : transaction ] ;
2017-09-22 22:40:44 +02:00
}
2017-09-22 21:15:04 +02:00
}
2017-09-13 21:35:33 +02:00
}
2017-09-13 18:14:22 +02:00
}
2018-10-30 16:21:26 +01:00
- ( void ) throws_handleEnvelope : ( SSKProtoEnvelope * ) envelope
plaintextData : ( NSData * ) plaintextData
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2018-10-30 16:21:26 +01:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2019-11-15 03:56:35 +01:00
serverID : ( uint64_t ) serverID
2016-12-06 03:32:11 +01:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! plaintextData ) {
OWSFailDebug ( @ "Missing plaintextData." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
if ( envelope . timestamp < 1 ) {
OWSFailDebug ( @ "Invalid timestamp." ) ;
return ;
}
if ( envelope . source . length < 1 ) {
OWSFailDebug ( @ "Missing source." ) ;
return ;
}
if ( envelope . sourceDevice < 1 ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Invalid source device." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-02-16 00:32:27 +01:00
BOOL duplicateEnvelope = [ self . incomingMessageFinder existsMessageWithTimestamp : envelope . timestamp
sourceId : envelope . source
2017-09-13 21:35:33 +02:00
sourceDeviceId : envelope . sourceDevice
transaction : transaction ] ;
2017-02-16 00:32:27 +01:00
if ( duplicateEnvelope ) {
2020-02-15 00:01:21 +01:00
OWSLogInfo ( @ "Ignoring previously received envelope from: %@ with timestamp: %llu." ,
2017-08-28 23:29:25 +02:00
envelopeAddress ( envelope ) ,
envelope . timestamp ) ;
2017-02-16 00:32:27 +01:00
return ;
}
2019-07-24 01:20:33 +02:00
2019-09-18 03:09:09 +02:00
// Loki : Handle friend request acceptance if needed
2020-02-15 00:01:21 +01:00
// The envelope type is set during UD decryption .
2019-09-18 03:09:09 +02:00
[ self handleFriendRequestAcceptanceIfNeededWithEnvelope : envelope transaction : transaction ] ;
2019-09-23 05:42:58 +02:00
2018-08-03 21:50:27 +02:00
if ( envelope . content ! = nil ) {
2018-08-02 15:34:50 +02:00
NSError * error ;
SSKProtoContent * _Nullable contentProto = [ SSKProtoContent parseData : plaintextData error : & error ] ;
if ( error || ! contentProto ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Could not parse proto due to error: %@." , error ) ;
2018-08-02 15:34:50 +02:00
return ;
}
2020-02-15 00:01:21 +01:00
OWSLogInfo ( @ "Handling content: <Content: %@>." , [ self descriptionForContent : contentProto ] ) ;
2019-05-13 04:19:05 +02:00
2019-11-27 04:54:45 +01:00
// Loki : Workaround for duplicate sync transcript issue
if ( contentProto . syncMessage ! = nil && contentProto . syncMessage . sent ! = nil ) {
BOOL isDuplicate = [ LKAPI isDuplicateSyncMessage : contentProto . syncMessage . sent from : envelope . source ] ;
if ( isDuplicate ) { return ; }
}
2019-11-29 05:23:18 +01:00
2019-10-31 06:52:22 +01:00
// Loki : Handle pre key bundle message if needed
2019-09-23 06:20:03 +02:00
if ( contentProto . prekeyBundleMessage ! = nil ) {
2019-09-23 05:42:58 +02:00
OWSLogInfo ( @ "[Loki] Received a pre key bundle message from: %@." , envelope . source ) ;
2019-11-07 02:21:49 +01:00
PreKeyBundle * _Nullable bundle = [ contentProto . prekeyBundleMessage getPreKeyBundleWithTransaction : transaction ] ;
2019-09-23 06:20:03 +02:00
if ( bundle = = nil ) {
2019-09-23 05:42:58 +02:00
OWSFailDebug ( @ "Failed to create a pre key bundle." ) ;
2020-01-30 10:16:31 +01:00
return ;
2019-05-13 04:19:05 +02:00
}
2019-05-14 04:33:48 +02:00
[ self . primaryStorage setPreKeyBundle : bundle forContact : envelope . source transaction : transaction ] ;
2019-12-09 06:27:00 +01:00
2020-02-15 00:01:21 +01:00
// Loki : If we received a friend request , but we were already friends with this user , reset the session
// The envelope type is set during UD decryption .
2019-12-09 06:27:00 +01:00
if ( envelope . type = = SSKProtoEnvelopeTypeFriendRequest ) {
TSContactThread * thread = [ TSContactThread getThreadWithContactId : envelope . source transaction : transaction ] ;
if ( thread && thread . isContactFriend ) {
[ self resetSessionWithContact : envelope . source transaction : transaction ] ;
2020-02-04 00:53:49 +01:00
// Let our other devices know that we have reset the session
2019-12-09 06:27:00 +01:00
[ SSKEnvironment . shared . syncManager syncContact : envelope . source transaction : transaction ] ;
}
}
2019-05-13 04:19:05 +02:00
}
2019-05-23 05:36:50 +02:00
2019-10-31 06:52:22 +01:00
// Loki : Handle address message if needed
2019-05-23 05:36:50 +02:00
if ( contentProto . lokiAddressMessage ) {
2019-05-24 07:20:49 +02:00
NSString * address = contentProto . lokiAddressMessage . ptpAddress ;
uint32_t port = contentProto . lokiAddressMessage . ptpPort ;
2019-06-12 06:50:36 +02:00
[ LKP2PAPI didReceiveLokiAddressMessageForContact : envelope . source address : address port : port receivedThroughP2P : envelope . isPtpMessage ] ;
2019-05-23 05:36:50 +02:00
}
2017-08-01 19:53:51 +02:00
2019-11-29 05:23:18 +01:00
// Loki : Handle device linking message if needed
if ( contentProto . lokiDeviceLinkMessage ! = nil ) {
NSString * masterHexEncodedPublicKey = contentProto . lokiDeviceLinkMessage . masterHexEncodedPublicKey ;
NSString * slaveHexEncodedPublicKey = contentProto . lokiDeviceLinkMessage . slaveHexEncodedPublicKey ;
NSData * masterSignature = contentProto . lokiDeviceLinkMessage . masterSignature ;
NSData * slaveSignature = contentProto . lokiDeviceLinkMessage . slaveSignature ;
if ( masterSignature ! = nil ) { // Authorization
OWSLogInfo ( @ "[Loki] Received a device linking authorization from: %@" , envelope . source ) ; // Not masterHexEncodedPublicKey
[ LKDeviceLinkingSession . current processLinkingAuthorizationFrom : masterHexEncodedPublicKey for : slaveHexEncodedPublicKey masterSignature : masterSignature slaveSignature : slaveSignature ] ;
2019-12-02 03:10:01 +01:00
// Set any profile info
2019-11-29 05:23:18 +01:00
if ( contentProto . dataMessage ) {
2019-12-02 01:01:07 +01:00
SSKProtoDataMessage * dataMessage = contentProto . dataMessage ;
[ self handleProfileNameUpdateIfNeeded : dataMessage recipientId : masterHexEncodedPublicKey transaction : transaction ] ;
[ self handleProfileKeyUpdateIfNeeded : dataMessage recipientId : masterHexEncodedPublicKey ] ;
2019-11-29 05:23:18 +01:00
}
} else if ( slaveSignature ! = nil ) { // Request
OWSLogInfo ( @ "[Loki] Received a device linking request from: %@" , envelope . source ) ; // Not slaveHexEncodedPublicKey
[ LKDeviceLinkingSession . current processLinkingRequestFrom : slaveHexEncodedPublicKey to : masterHexEncodedPublicKey with : slaveSignature ] ;
}
} else if ( contentProto . syncMessage ) {
2018-10-30 16:21:26 +01:00
[ self throws_handleIncomingEnvelope : envelope
withSyncMessage : contentProto . syncMessage
2019-11-15 03:56:35 +01:00
transaction : transaction
serverID : serverID ] ;
2017-11-16 15:54:55 +01:00
[ [ OWSDeviceManager sharedManager ] setHasReceivedSyncMessage ] ;
2018-08-08 19:41:12 +02:00
} else if ( contentProto . dataMessage ) {
2018-12-02 23:30:31 +01:00
[ self handleIncomingEnvelope : envelope
withDataMessage : contentProto . dataMessage
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2018-08-08 19:41:12 +02:00
} else if ( contentProto . callMessage ) {
2018-08-02 15:34:50 +02:00
[ self handleIncomingEnvelope : envelope withCallMessage : contentProto . callMessage ] ;
2018-10-31 00:18:17 +01:00
} else if ( contentProto . typingMessage ) {
[ self handleIncomingEnvelope : envelope withTypingMessage : contentProto . typingMessage transaction : transaction ] ;
2018-08-08 19:41:12 +02:00
} else if ( contentProto . nullMessage ) {
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "Received null message." ) ;
2018-08-08 19:41:12 +02:00
} else if ( contentProto . receiptMessage ) {
2018-08-02 15:34:50 +02:00
[ self handleIncomingEnvelope : envelope
withReceiptMessage : contentProto . receiptMessage
transaction : transaction ] ;
2016-08-23 22:38:05 +02:00
} else {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "Ignoring envelope. Content with no known payload" ) ;
2016-08-22 22:09:58 +02:00
}
2018-08-03 21:50:27 +02:00
} else if ( envelope . legacyMessage ! = nil ) { // DEPRECATED - Remove after all clients have been upgraded .
2018-08-02 15:34:50 +02:00
NSError * error ;
SSKProtoDataMessage * _Nullable dataMessageProto = [ SSKProtoDataMessage parseData : plaintextData error : & error ] ;
if ( error || ! dataMessageProto ) {
2018-08-27 18:51:32 +02:00
OWSFailDebug ( @ "could not parse proto: %@" , error ) ;
2018-08-02 15:34:50 +02:00
return ;
}
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "handling message: <DataMessage: %@ />" , [ self descriptionForDataMessage : dataMessageProto ] ) ;
2017-08-04 15:33:56 +02:00
2018-12-02 23:30:31 +01:00
[ self handleIncomingEnvelope : envelope
withDataMessage : dataMessageProto
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2016-12-06 03:32:11 +01:00
} else {
2018-07-25 22:00:25 +02:00
OWSProdInfoWEnvelope ( [ OWSAnalyticsEvents messageManagerErrorEnvelopeNoActionablePayload ] , envelope ) ;
2015-12-07 03:31:43 +01:00
}
}
2018-08-01 16:45:21 +02:00
- ( void ) handleIncomingEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
withDataMessage : ( SSKProtoDataMessage * ) dataMessage
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-07-31 02:40:14 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2020-01-20 06:58:38 +01:00
2020-02-15 00:01:21 +01:00
// Loki : Don ' t process session request messages any further
2020-01-20 06:58:38 +01:00
if ( ( dataMessage . flags & SSKProtoDataMessageFlagsSessionRequest ) ! = 0 ) { return ; }
2020-02-15 00:01:21 +01:00
// Loki : Don ' t process session restore messages any further
2019-12-09 06:27:00 +01:00
if ( ( dataMessage . flags & SSKProtoDataMessageFlagsSessionRestore ) ! = 0 ) { return ; }
2020-01-20 06:58:38 +01:00
2018-09-09 20:35:52 +02:00
if ( [ self isDataMessageBlocked : dataMessage envelope : envelope ] ) {
2020-02-15 00:01:21 +01:00
NSString * logMessage = [ NSString stringWithFormat : @ "Ignoring blocked message from sender: %@." , envelope . source ] ;
2018-09-09 20:35:52 +02:00
if ( dataMessage . group ) {
2018-12-18 22:15:25 +01:00
logMessage = [ logMessage stringByAppendingFormat : @ " in group: %@" , dataMessage . group . id ] ;
2018-09-09 20:35:52 +02:00
}
2018-09-15 16:17:08 +02:00
OWSLogError ( @ "%@" , logMessage ) ;
2018-09-09 20:35:52 +02:00
return ;
}
2018-02-02 16:56:16 +01:00
if ( dataMessage . hasTimestamp ) {
if ( dataMessage . timestamp <= 0 ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Ignoring data message with invalid timestamp: %@." , envelope . source ) ;
2018-02-02 16:56:16 +01:00
return ;
}
// This prevents replay attacks by the service .
if ( dataMessage . timestamp ! = envelope . timestamp ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Ignoring data message with non-matching timestamp: %@." , envelope . source ) ;
2018-02-02 16:56:16 +01:00
return ;
}
}
2019-11-29 00:18:04 +01:00
[ self handleProfileKeyUpdateIfNeeded : dataMessage recipientId : envelope . source ] ;
2018-02-02 16:56:16 +01:00
2018-08-08 19:41:12 +02:00
if ( dataMessage . group ) {
2017-10-04 16:06:38 +02:00
TSGroupThread * _Nullable groupThread =
2017-10-03 19:41:48 +02:00
[ TSGroupThread threadWithGroupId : dataMessage . group . id transaction : transaction ] ;
2017-10-04 16:06:38 +02:00
2018-09-12 23:06:21 +02:00
if ( groupThread ) {
if ( dataMessage . group . type ! = SSKProtoGroupContextTypeUpdate ) {
2020-01-30 05:51:46 +01:00
if ( ! [ groupThread isLocalUserInGroupWithTransaction : transaction ] ) {
2018-09-15 16:17:08 +02:00
OWSLogInfo ( @ "Ignoring messages for left group." ) ;
2018-09-12 23:06:21 +02:00
return ;
}
}
} else {
2017-10-04 16:06:38 +02:00
// Unknown group .
2018-08-01 23:13:01 +02:00
if ( dataMessage . group . type = = SSKProtoGroupContextTypeUpdate ) {
2017-10-04 16:06:38 +02:00
// Accept group updates for unknown groups .
2018-08-01 23:13:01 +02:00
} else if ( dataMessage . group . type = = SSKProtoGroupContextTypeDeliver ) {
2017-10-04 16:06:38 +02:00
[ self sendGroupInfoRequest : dataMessage . group . id envelope : envelope transaction : transaction ] ;
2017-10-03 19:41:48 +02:00
return ;
2017-10-04 16:06:38 +02:00
} else {
2020-02-15 00:01:21 +01:00
OWSLogInfo ( @ "Ignoring group message for unknown group from: %@." , envelope . source ) ;
2017-08-08 18:16:17 +02:00
return ;
}
2015-12-07 03:31:43 +01:00
}
}
2017-09-21 20:03:24 +02:00
2018-08-01 23:13:01 +02:00
if ( ( dataMessage . flags & SSKProtoDataMessageFlagsEndSession ) ! = 0 ) {
2017-09-13 21:35:33 +02:00
[ self handleEndSessionMessageWithEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
2018-08-01 23:13:01 +02:00
} else if ( ( dataMessage . flags & SSKProtoDataMessageFlagsExpirationTimerUpdate ) ! = 0 ) {
2017-09-13 21:35:33 +02:00
[ self handleExpirationTimerUpdateMessageWithEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
2018-08-01 23:13:01 +02:00
} else if ( ( dataMessage . flags & SSKProtoDataMessageFlagsProfileKeyUpdate ) ! = 0 ) {
2017-09-13 21:35:33 +02:00
[ self handleProfileKeyMessageWithEnvelope : envelope dataMessage : dataMessage ] ;
2019-11-20 06:27:34 +01:00
} else if ( ( dataMessage . flags & SSKProtoDataMessageFlagsUnlinkDevice ) ! = 0 ) {
[ self handleUnlinkDeviceMessageWithEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
2016-10-14 23:00:29 +02:00
} else if ( dataMessage . attachments . count > 0 ) {
2018-12-02 23:30:31 +01:00
[ self handleReceivedMediaWithEnvelope : envelope
dataMessage : dataMessage
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2015-12-07 03:31:43 +01:00
} else {
2018-12-02 23:30:31 +01:00
[ self handleReceivedTextMessageWithEnvelope : envelope
dataMessage : dataMessage
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2017-10-03 19:41:48 +02:00
2016-10-14 23:00:29 +02:00
if ( [ self isDataMessageGroupAvatarUpdate : dataMessage ] ) {
2018-08-27 18:51:32 +02:00
OWSLogVerbose ( @ "Data message had group avatar attachment" ) ;
2017-09-13 21:35:33 +02:00
[ self handleReceivedGroupAvatarUpdateWithEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
2016-10-14 23:00:29 +02:00
}
}
2018-10-11 18:51:58 +02:00
2018-10-11 18:52:49 +02:00
// Send delivery receipts for "valid data" messages received via UD .
if ( wasReceivedByUD ) {
2018-10-11 21:29:01 +02:00
[ self . outgoingReceiptManager enqueueDeliveryReceiptForEnvelope : envelope ] ;
2018-10-11 18:52:49 +02:00
}
2018-10-11 18:51:58 +02:00
}
2017-10-03 19:41:48 +02:00
- ( void ) sendGroupInfoRequest : ( NSData * ) groupId
2018-08-01 16:45:21 +02:00
envelope : ( SSKProtoEnvelope * ) envelope
2017-10-03 19:41:48 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-10-03 19:41:48 +02:00
if ( groupId . length < 1 ) {
2018-08-30 16:31:01 +02:00
OWSFailDebug ( @ "Invalid groupId." ) ;
2017-10-03 19:41:48 +02:00
return ;
}
2018-02-07 23:00:45 +01:00
// FIXME : https : // github . com / signalapp / Signal - iOS / issues / 1340
2018-08-27 18:55:37 +02:00
OWSLogInfo ( @ "Sending group info request: %@" , envelopeAddress ( envelope ) ) ;
2017-10-03 19:41:48 +02:00
NSString * recipientId = envelope . source ;
TSThread * thread = [ TSContactThread getOrCreateThreadWithContactId : recipientId transaction : transaction ] ;
OWSSyncGroupsRequestMessage * syncGroupsRequestMessage =
[ [ OWSSyncGroupsRequestMessage alloc ] initWithThread : thread groupId : groupId ] ;
2018-10-20 19:51:48 +02:00
[ self . messageSenderJobQueue addMessage : syncGroupsRequestMessage transaction : transaction ] ;
2017-10-03 19:41:48 +02:00
}
2018-08-01 16:45:21 +02:00
- ( void ) handleIncomingEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
withReceiptMessage : ( SSKProtoReceiptMessage * ) receiptMessage
2017-09-22 22:40:44 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2017-09-15 21:28:44 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! receiptMessage ) {
OWSFailDebug ( @ "Missing receiptMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-22 22:40:44 +02:00
2018-08-02 15:34:50 +02:00
NSArray < NSNumber * > * sentTimestamps = receiptMessage . timestamp ;
2017-09-15 21:28:44 +02:00
switch ( receiptMessage . type ) {
2018-08-01 23:13:01 +02:00
case SSKProtoReceiptMessageTypeDelivery :
2018-08-27 18:51:32 +02:00
OWSLogVerbose ( @ "Processing receipt message with delivery receipts." ) ;
2017-09-27 20:19:26 +02:00
[ self processDeliveryReceiptsFromRecipientId : envelope . source
sentTimestamps : sentTimestamps
deliveryTimestamp : @ ( envelope . timestamp )
transaction : transaction ] ;
2017-09-15 21:28:44 +02:00
return ;
2018-08-01 23:13:01 +02:00
case SSKProtoReceiptMessageTypeRead :
2018-08-27 18:51:32 +02:00
OWSLogVerbose ( @ "Processing receipt message with read receipts." ) ;
2017-09-22 22:40:44 +02:00
[ OWSReadReceiptManager . sharedManager processReadReceiptsFromRecipientId : envelope . source
sentTimestamps : sentTimestamps
readTimestamp : envelope . timestamp ] ;
2017-09-15 21:28:44 +02:00
break ;
default :
2018-08-27 18:55:37 +02:00
OWSLogInfo ( @ "Ignoring receipt message of unknown type: %d." , ( int ) receiptMessage . type ) ;
2017-09-15 21:28:44 +02:00
return ;
}
}
2018-08-01 16:45:21 +02:00
- ( void ) handleIncomingEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
withCallMessage : ( SSKProtoCallMessage * ) callMessage
2016-12-18 22:08:26 +01:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! callMessage ) {
OWSFailDebug ( @ "Missing callMessage." ) ;
return ;
}
2017-08-04 15:33:56 +02:00
if ( [ callMessage hasProfileKey ] ) {
NSData * profileKey = [ callMessage profileKey ] ;
2017-09-13 21:35:33 +02:00
NSString * recipientId = envelope . source ;
2017-08-25 23:16:49 +02:00
[ self . profileManager setProfileKeyData : profileKey forRecipientId : recipientId ] ;
2017-08-04 15:33:56 +02:00
}
2017-09-20 17:48:37 +02:00
// By dispatching async , we introduce the possibility that these messages might be lost
// if the app exits before this block is executed . This is fine , since the call by
// definition will end if the app exits .
2017-09-13 21:35:33 +02:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2018-08-08 19:41:12 +02:00
if ( callMessage . offer ) {
2017-09-13 21:35:33 +02:00
[ self . callMessageHandler receivedOffer : callMessage . offer fromCallerId : envelope . source ] ;
2018-08-08 19:41:12 +02:00
} else if ( callMessage . answer ) {
2017-09-13 21:35:33 +02:00
[ self . callMessageHandler receivedAnswer : callMessage . answer fromCallerId : envelope . source ] ;
} else if ( callMessage . iceUpdate . count > 0 ) {
2018-08-01 23:13:01 +02:00
for ( SSKProtoCallMessageIceUpdate * iceUpdate in callMessage . iceUpdate ) {
2017-09-13 21:35:33 +02:00
[ self . callMessageHandler receivedIceUpdate : iceUpdate fromCallerId : envelope . source ] ;
}
2018-08-08 19:41:12 +02:00
} else if ( callMessage . hangup ) {
2018-08-27 18:51:32 +02:00
OWSLogVerbose ( @ "Received CallMessage with Hangup." ) ;
2017-09-13 21:35:33 +02:00
[ self . callMessageHandler receivedHangup : callMessage . hangup fromCallerId : envelope . source ] ;
2018-08-08 19:41:12 +02:00
} else if ( callMessage . busy ) {
2017-09-13 21:35:33 +02:00
[ self . callMessageHandler receivedBusy : callMessage . busy fromCallerId : envelope . source ] ;
} else {
OWSProdInfoWEnvelope ( [ OWSAnalyticsEvents messageManagerErrorCallMessageNoActionablePayload ] , envelope ) ;
2016-12-18 22:08:26 +01:00
}
2017-09-13 21:35:33 +02:00
} ) ;
2016-12-18 22:08:26 +01:00
}
2018-10-31 00:18:17 +01:00
- ( void ) handleIncomingEnvelope : ( SSKProtoEnvelope * ) envelope
withTypingMessage : ( SSKProtoTypingMessage * ) typingMessage
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
OWSAssertDebug ( transaction ) ;
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! typingMessage ) {
OWSFailDebug ( @ "Missing typingMessage." ) ;
return ;
}
2018-11-06 23:21:24 +01:00
if ( typingMessage . timestamp ! = envelope . timestamp ) {
OWSFailDebug ( @ "typingMessage has invalid timestamp." ) ;
return ;
}
2018-11-07 16:09:11 +01:00
NSString * localNumber = self . tsAccountManager . localNumber ;
if ( [ localNumber isEqualToString : envelope . source ] ) {
OWSLogVerbose ( @ "Ignoring typing indicators from self or linked device." ) ;
2018-11-07 16:56:40 +01:00
return ;
2018-12-18 22:23:25 +01:00
} else if ( [ self . blockingManager isRecipientIdBlocked : envelope . source ]
2018-12-18 22:15:25 +01:00
|| ( typingMessage . hasGroupID && [ self . blockingManager isGroupIdBlocked : typingMessage . groupID ] ) ) {
NSString * logMessage = [ NSString stringWithFormat : @ "Ignoring blocked message from sender: %@" , envelope . source ] ;
if ( typingMessage . hasGroupID ) {
logMessage = [ logMessage stringByAppendingFormat : @ " in group: %@" , typingMessage . groupID ] ;
}
OWSLogError ( @ "%@" , logMessage ) ;
return ;
2018-11-07 16:09:11 +01:00
}
2018-10-31 00:18:17 +01:00
TSThread * _Nullable thread ;
if ( typingMessage . hasGroupID ) {
2018-12-18 22:15:25 +01:00
TSGroupThread * groupThread = [ TSGroupThread threadWithGroupId : typingMessage . groupID transaction : transaction ] ;
2020-01-30 05:51:46 +01:00
if ( ! [ groupThread isLocalUserInGroupWithTransaction : transaction ] ) {
2018-12-18 22:15:25 +01:00
OWSLogInfo ( @ "Ignoring messages for left group." ) ;
return ;
}
thread = groupThread ;
2018-10-31 00:18:17 +01:00
} else {
thread = [ TSContactThread getThreadWithContactId : envelope . source transaction : transaction ] ;
}
2018-12-18 22:15:25 +01:00
2018-10-31 00:18:17 +01:00
if ( ! thread ) {
// This isn ' t neccesarily an error . We might not yet know about the thread ,
// in which case we don ' t need to display the typing indicators .
OWSLogWarn ( @ "Could not locate thread for typingMessage." ) ;
return ;
}
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
switch ( typingMessage . action ) {
case SSKProtoTypingMessageActionStarted :
[ self . typingIndicators didReceiveTypingStartedMessageInThread : thread
recipientId : envelope . source
deviceId : envelope . sourceDevice ] ;
break ;
case SSKProtoTypingMessageActionStopped :
[ self . typingIndicators didReceiveTypingStoppedMessageInThread : thread
recipientId : envelope . source
deviceId : envelope . sourceDevice ] ;
break ;
default :
OWSFailDebug ( @ "Typing message has unexpected action." ) ;
break ;
}
} ) ;
}
2018-08-01 16:45:21 +02:00
- ( void ) handleReceivedGroupAvatarUpdateWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-10-14 23:00:29 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2017-10-03 19:41:48 +02:00
TSGroupThread * _Nullable groupThread =
[ TSGroupThread threadWithGroupId : dataMessage . group . id transaction : transaction ] ;
if ( ! groupThread ) {
2018-08-27 18:51:32 +02:00
OWSFailDebug ( @ "Missing group for group avatar update" ) ;
2017-10-03 19:41:48 +02:00
return ;
}
2018-11-07 23:49:25 +01:00
TSAttachmentPointer * _Nullable avatarPointer =
2018-11-07 23:42:40 +01:00
[ TSAttachmentPointer attachmentPointerFromProto : dataMessage . group . avatar albumMessage : nil ] ;
2016-10-14 23:00:29 +02:00
2018-11-07 23:49:25 +01:00
if ( ! avatarPointer ) {
OWSLogWarn ( @ "received unsupported group avatar envelope" ) ;
return ;
}
[ self . attachmentDownloads downloadAttachmentPointer : avatarPointer
2018-11-02 17:11:15 +01:00
success : ^ ( NSArray < TSAttachmentStream * > * attachmentStreams ) {
OWSAssertDebug ( attachmentStreams . count = = 1 ) ;
TSAttachmentStream * attachmentStream = attachmentStreams . firstObject ;
2016-10-14 23:00:29 +02:00
[ groupThread updateAvatarWithAttachmentStream : attachmentStream ] ;
}
2017-05-10 16:05:01 +02:00
failure : ^ ( NSError * error ) {
2018-08-27 18:51:32 +02:00
OWSLogError ( @ "failed to fetch attachments for group avatar sent at: %llu. with error: %@" ,
2016-10-14 23:00:29 +02:00
envelope . timestamp ,
error ) ;
} ] ;
}
2018-08-01 16:45:21 +02:00
- ( void ) handleReceivedMediaWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-10-14 23:00:29 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2017-10-03 19:41:48 +02:00
TSThread * _Nullable thread = [ self threadForEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
if ( ! thread ) {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Ignoring media message for unknown group." ) ;
2017-10-03 19:41:48 +02:00
return ;
}
2018-12-03 22:28:01 +01:00
TSIncomingMessage * _Nullable message = [ self handleReceivedEnvelope : envelope
withDataMessage : dataMessage
2018-12-03 22:24:24 +01:00
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2016-10-14 23:00:29 +02:00
2018-11-07 23:49:25 +01:00
if ( ! message ) {
return ;
2018-11-07 23:42:40 +01:00
}
2018-11-07 23:49:25 +01:00
[ message saveWithTransaction : transaction ] ;
2017-06-13 16:50:42 +02:00
2020-02-15 00:01:21 +01:00
OWSLogDebug ( @ "Incoming attachment message: %@." , message . debugDescription ) ;
2018-11-07 23:42:40 +01:00
2018-11-07 23:49:25 +01:00
[ self . attachmentDownloads downloadAttachmentsForMessage : message
2017-09-13 21:35:33 +02:00
transaction : transaction
2018-11-02 17:11:15 +01:00
success : ^ ( NSArray < TSAttachmentStream * > * attachmentStreams ) {
2020-02-15 00:01:21 +01:00
OWSLogDebug ( @ "Successfully fetched attachments: %lu for message: %@." ,
2018-11-02 17:11:15 +01:00
( unsigned long ) attachmentStreams . count ,
2018-11-07 23:49:25 +01:00
message ) ;
2016-10-14 23:00:29 +02:00
}
2017-05-10 16:05:01 +02:00
failure : ^ ( NSError * error ) {
2020-02-15 00:01:21 +01:00
OWSLogError ( @ "Failed to fetch attachments for message: %@ with error: %@." , message , error ) ;
2016-10-14 23:00:29 +02:00
} ] ;
2015-12-07 03:31:43 +01:00
}
2018-10-30 16:21:26 +01:00
- ( void ) throws_handleIncomingEnvelope : ( SSKProtoEnvelope * ) envelope
withSyncMessage : ( SSKProtoSyncMessage * ) syncMessage
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2019-11-15 03:56:35 +01:00
serverID : ( uint64_t ) serverID
2016-08-23 22:38:05 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! syncMessage ) {
OWSFailDebug ( @ "Missing syncMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2019-11-08 04:59:36 +01:00
NSString * userHexEncodedPublicKey = OWSIdentityManager . sharedManager . identityKeyPair . hexEncodedPublicKey ;
NSSet < NSString * > * linkedDeviceHexEncodedPublicKeys = [ LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor : userHexEncodedPublicKey in : transaction ] ;
if ( ! [ linkedDeviceHexEncodedPublicKeys contains : ^ BOOL ( NSString * hexEncodedPublicKey ) {
return [ hexEncodedPublicKey isEqual : envelope . source ] ;
} ] ) {
OWSProdErrorWEnvelope ( [ OWSAnalyticsEvents messageManagerErrorSyncMessageFromUnknownSource ] , envelope ) ;
return ;
}
2019-11-29 05:23:18 +01:00
NSString * masterHexEncodedPublicKey = [ LKDatabaseUtilities getMasterHexEncodedPublicKeyFor : userHexEncodedPublicKey in : transaction ] ;
BOOL wasSentByMasterDevice = [ masterHexEncodedPublicKey isEqual : envelope . source ] ;
2018-08-08 19:41:12 +02:00
if ( syncMessage . sent ) {
2019-11-29 05:23:18 +01:00
OWSIncomingSentMessageTranscript * transcript =
[ [ OWSIncomingSentMessageTranscript alloc ] initWithProto : syncMessage . sent transaction : transaction ] ;
SSKProtoDataMessage * _Nullable dataMessage = syncMessage . sent . message ;
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
2019-12-02 01:01:07 +01:00
// Loki : Try to update using the provided profile
if ( wasSentByMasterDevice ) {
[ self handleProfileNameUpdateIfNeeded : dataMessage recipientId : masterHexEncodedPublicKey transaction : transaction ] ;
[ self handleProfileKeyUpdateIfNeeded : dataMessage recipientId : masterHexEncodedPublicKey ] ;
}
2019-11-29 05:23:18 +01:00
NSString * destination = syncMessage . sent . destination ;
if ( dataMessage && destination . length > 0 && dataMessage . hasProfileKey ) {
// If we observe a linked device sending our profile key to another
// user , we can infer that that user belongs in our profile whitelist .
if ( dataMessage . group ) {
[ self . profileManager addGroupIdToProfileWhitelist : dataMessage . group . id ] ;
} else {
[ self . profileManager addUserToProfileWhitelist : destination ] ;
}
}
if ( [ self isDataMessageGroupAvatarUpdate : syncMessage . sent . message ] && ! syncMessage . sent . isRecipientUpdate ) {
[ OWSRecordTranscriptJob
processIncomingSentMessageTranscript : transcript
serverID : 0
attachmentHandler : ^ ( NSArray < TSAttachmentStream * > * attachmentStreams ) {
OWSAssertDebug ( attachmentStreams . count = = 1 ) ;
TSAttachmentStream * attachmentStream = attachmentStreams . firstObject ;
[ self . dbConnection readWriteWithBlock : ^ (
YapDatabaseReadWriteTransaction * transaction ) {
TSGroupThread * _Nullable groupThread =
[ TSGroupThread threadWithGroupId : dataMessage . group . id
transaction : transaction ] ;
if ( ! groupThread ) {
OWSFailDebug ( @ "ignoring sync group avatar update for unknown group." ) ;
return ;
2019-11-27 06:26:15 +01:00
}
2019-11-29 05:23:18 +01:00
[ groupThread updateAvatarWithAttachmentStream : attachmentStream
transaction : transaction ] ;
} ] ;
2019-11-27 06:26:15 +01:00
}
2019-11-29 05:23:18 +01:00
transaction : transaction ] ;
2016-10-14 23:00:29 +02:00
} else {
2020-01-30 05:51:46 +01:00
if ( transcript . isGroupUpdate ) {
// TODO : This code is pretty much a duplicate of the code in OWSRecordTranscriptJob
TSGroupThread * newGroupThread = [ TSGroupThread getOrCreateThreadWithGroupId : transcript . dataMessage . group . id groupType : closedGroup transaction : transaction ] ;
TSGroupModel * newGroupModel = [ [ TSGroupModel alloc ] initWithTitle : transcript . dataMessage . group . name
memberIds : transcript . dataMessage . group . members
image : nil
groupId : transcript . dataMessage . group . id
groupType : closedGroup
adminIds : transcript . dataMessage . group . admins ] ;
NSString * updateMessage = [ newGroupThread . groupModel getInfoStringAboutUpdateTo : newGroupModel contactsManager : self . contactsManager ] ;
newGroupThread . groupModel = newGroupModel ;
[ newGroupThread saveWithTransaction : transaction ] ;
// Loki : Try to establish sessions with all members when a group is created or updated
[ self establishSessionsWithMembersIfNeeded : transcript . dataMessage . group . members forThread : newGroupThread transaction : transaction ] ;
[ [ OWSDisappearingMessagesJob sharedJob ] becomeConsistentWithDisappearingDuration : transcript . dataMessage . expireTimer
thread : newGroupThread
createdByRemoteRecipientId : nil
createdInExistingGroup : YES
transaction : transaction ] ;
TSInfoMessage * infoMessage = [ [ TSInfoMessage alloc ] initWithTimestamp : NSDate . ows_millisecondTimeStamp
inThread : newGroupThread
messageType : TSInfoMessageTypeGroupUpdate
customMessage : updateMessage ] ;
[ infoMessage saveWithTransaction : transaction ] ;
2020-02-16 23:19:25 +01:00
} else if ( transcript . isGroupQuit ) {
TSGroupThread * groupThread = [ TSGroupThread getOrCreateThreadWithGroupId : transcript . dataMessage . group . id groupType : closedGroup transaction : transaction ] ;
[ groupThread leaveGroupWithTransaction : transaction ] ;
TSInfoMessage * infoMessage = [ [ TSInfoMessage alloc ] initWithTimestamp : NSDate . ows_millisecondTimeStamp
inThread : groupThread
messageType : TSInfoMessageTypeGroupQuit
customMessage : NSLocalizedString ( @ "GROUP_YOU_LEFT" , nil ) ] ;
[ infoMessage saveWithTransaction : transaction ] ;
2020-01-30 05:51:46 +01:00
} else {
[ OWSRecordTranscriptJob
processIncomingSentMessageTranscript : transcript
serverID : ( serverID ? : 0 )
attachmentHandler : ^ ( NSArray < TSAttachmentStream * > * attachmentStreams ) {
OWSLogDebug ( @ "successfully fetched transcript attachments: %lu" ,
( unsigned long ) attachmentStreams . count ) ;
}
transaction : transaction ] ;
2019-11-27 06:26:15 +01:00
}
2016-10-14 23:00:29 +02:00
}
2018-08-08 19:41:12 +02:00
} else if ( syncMessage . request ) {
2018-08-01 23:13:01 +02:00
if ( syncMessage . request . type = = SSKProtoSyncMessageRequestTypeContacts ) {
2017-11-21 16:01:55 +01:00
// We respond asynchronously because populating the sync message will
// create transactions and it ' s not practical ( due to locking in the OWSIdentityManager )
// to plumb our transaction through .
//
// In rare cases this means we won ' t respond to the sync request , but that ' s
// acceptable .
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ {
2018-12-11 16:24:06 +01:00
[ [ self . syncManager syncAllContacts ] retainUntilComplete ] ;
2017-11-21 16:01:55 +01:00
} ) ;
2018-08-01 23:13:01 +02:00
} else if ( syncMessage . request . type = = SSKProtoSyncMessageRequestTypeGroups ) {
2020-02-17 00:12:40 +01:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ {
[ [ self . syncManager syncAllGroups ] retainUntilComplete ] ;
} ) ;
2018-08-01 23:13:01 +02:00
} else if ( syncMessage . request . type = = SSKProtoSyncMessageRequestTypeBlocked ) {
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "Received request for block list" ) ;
2018-09-20 18:52:43 +02:00
[ self . blockingManager syncBlockList ] ;
2018-08-01 23:13:01 +02:00
} else if ( syncMessage . request . type = = SSKProtoSyncMessageRequestTypeConfiguration ) {
2018-10-16 22:02:37 +02:00
[ SSKEnvironment . shared . syncManager sendConfigurationSyncMessage ] ;
2016-11-22 18:14:39 +01:00
} else {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "ignoring unsupported sync request message" ) ;
2016-08-26 01:01:35 +02:00
}
2018-08-08 19:41:12 +02:00
} else if ( syncMessage . blocked ) {
2017-09-28 16:01:17 +02:00
NSArray < NSString * > * blockedPhoneNumbers = [ syncMessage . blocked . numbers copy ] ;
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ {
2018-05-11 16:36:40 +02:00
[ self . blockingManager setBlockedPhoneNumbers : blockedPhoneNumbers sendSyncMessage : NO ] ;
2017-09-13 21:35:33 +02:00
} ) ;
2016-09-01 16:28:35 +02:00
} else if ( syncMessage . read . count > 0 ) {
2018-08-30 16:31:01 +02:00
OWSLogInfo ( @ "Received %lu read receipt(s)" , ( unsigned long ) syncMessage . read . count ) ;
2017-09-26 17:45:22 +02:00
[ OWSReadReceiptManager . sharedManager processReadReceiptsFromLinkedDevice : syncMessage . read
2018-04-18 02:53:27 +02:00
readTimestamp : envelope . timestamp
2017-09-26 17:45:22 +02:00
transaction : transaction ] ;
2018-08-08 19:41:12 +02:00
} else if ( syncMessage . verified ) {
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "Received verification state for %@" , syncMessage . verified . destination ) ;
2018-10-30 16:21:26 +01:00
[ self . identityManager throws_processIncomingSyncMessage : syncMessage . verified transaction : transaction ] ;
2019-11-29 05:23:18 +01:00
} else if ( syncMessage . contacts ! = nil ) {
2019-12-02 01:01:07 +01:00
if ( wasSentByMasterDevice && syncMessage . contacts . data . length > 0 ) {
2020-02-28 03:58:45 +01:00
[ LKLogger print : @ "[Loki] Received contact sync message." ] ;
2019-11-29 05:23:18 +01:00
NSData * data = syncMessage . contacts . data ;
ContactParser * parser = [ [ ContactParser alloc ] initWithData : data ] ;
NSArray < NSString * > * hexEncodedPublicKeys = [ parser parseHexEncodedPublicKeys ] ;
// Try to establish sessions
for ( NSString * hexEncodedPublicKey in hexEncodedPublicKeys ) {
TSContactThread * thread = [ TSContactThread getOrCreateThreadWithContactId : hexEncodedPublicKey transaction : transaction ] ;
LKThreadFriendRequestStatus friendRequestStatus = thread . friendRequestStatus ;
switch ( friendRequestStatus ) {
case LKThreadFriendRequestStatusNone : {
OWSMessageSender * messageSender = SSKEnvironment . shared . messageSender ;
2020-02-28 03:58:45 +01:00
LKFriendRequestMessage * automatedFriendRequestMessage = [ messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey : hexEncodedPublicKey transaction : transaction ] ;
2020-03-04 04:33:01 +01:00
thread . isForceHidden = true ;
[ thread saveWithTransaction : transaction ] ;
[ messageSender sendMessage : automatedFriendRequestMessage
success : ^ {
[ automatedFriendRequestMessage remove ] ;
thread . isForceHidden = false ;
[ thread save ] ;
}
failure : ^ ( NSError * error ) {
[ automatedFriendRequestMessage remove ] ;
thread . isForceHidden = false ;
[ thread save ] ;
} ] ;
2019-11-29 05:23:18 +01:00
break ;
}
case LKThreadFriendRequestStatusRequestReceived : {
[ thread saveFriendRequestStatus : LKThreadFriendRequestStatusFriends withTransaction : transaction ] ;
// The two lines below are equivalent to calling [ ThreadUtil enqueueFriendRequestAcceptanceMessageInThread : thread ]
LKEphemeralMessage * backgroundMessage = [ [ LKEphemeralMessage alloc ] initInThread : thread ] ;
[ self . messageSenderJobQueue addMessage : backgroundMessage transaction : transaction ] ;
break ;
}
default : break ; // Do nothing
}
}
}
2020-02-12 06:31:37 +01:00
} else if ( syncMessage . groups ! = nil ) {
if ( wasSentByMasterDevice && syncMessage . groups . data . length > 0 ) {
2020-02-28 03:58:45 +01:00
[ LKLogger print : @ "[Loki] Received group sync message." ] ;
2020-02-12 06:31:37 +01:00
NSData * data = syncMessage . groups . data ;
2020-02-12 07:08:27 +01:00
GroupParser * parser = [ [ GroupParser alloc ] initWithData : data ] ;
2020-02-12 07:14:52 +01:00
NSArray < TSGroupModel * > * groupModels = [ parser parseGroupModels ] ;
for ( TSGroupModel * groupModel in groupModels ) {
2020-02-25 00:34:59 +01:00
TSGroupThread * thread = [ TSGroupThread threadWithGroupId : groupModel . groupId transaction : transaction ] ;
if ( thread = = nil ) {
thread = [ TSGroupThread getOrCreateThreadWithGroupModel : groupModel transaction : transaction ] ;
[ thread saveWithTransaction : transaction ] ;
[ self establishSessionsWithMembersIfNeeded : groupModel . groupMemberIds forThread : thread transaction : transaction ] ;
TSInfoMessage * infoMessage = [ [ TSInfoMessage alloc ] initWithTimestamp : NSDate . ows_millisecondTimeStamp
inThread : thread
messageType : TSInfoMessageTypeGroupUpdate
customMessage : @ "You have joined the group." ] ;
[ infoMessage saveWithTransaction : transaction ] ;
}
2020-02-12 07:14:52 +01:00
}
2020-02-12 06:31:37 +01:00
}
2020-02-25 05:42:38 +01:00
} else if ( syncMessage . openGroups ! = nil ) {
if ( wasSentByMasterDevice && syncMessage . openGroups . count > 0 ) {
OWSLogInfo ( @ "[Loki] Received open group sync message." ) ;
for ( SSKProtoSyncMessageOpenGroups * openGroup in syncMessage . openGroups ) {
2020-02-25 06:19:56 +01:00
[ LKPublicChatManager . shared addChatWithServer : openGroup . url channel : openGroup . channel ] ;
2020-02-25 05:42:38 +01:00
}
}
2016-08-23 22:38:05 +02:00
} else {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "Ignoring unsupported sync message." ) ;
2016-08-23 22:38:05 +02:00
}
}
2018-08-01 16:45:21 +02:00
- ( void ) handleEndSessionMessageWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-08-22 22:09:58 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2019-12-09 06:27:00 +01:00
[ self resetSessionWithContact : envelope . source transaction : transaction ] ;
}
- ( void ) resetSessionWithContact : ( NSString * ) hexEncodedPublicKey
transaction : ( YapDatabaseReadWriteTransaction * ) transaction {
TSContactThread * thread = [ TSContactThread getOrCreateThreadWithContactId : hexEncodedPublicKey transaction : transaction ] ;
2017-09-13 21:35:33 +02:00
2018-10-03 23:41:43 +02:00
// MJK TODO - safe to remove senderTimestamp
2019-05-20 03:20:03 +02:00
[ [ [ TSInfoMessage alloc ] initWithTimestamp : NSDate . ows_millisecondTimeStamp
2019-05-17 02:11:06 +02:00
inThread : thread
2019-05-20 03:20:03 +02:00
messageType : TSInfoMessageTypeLokiSessionResetInProgress ] saveWithTransaction : transaction ] ;
2019-05-17 02:11:06 +02:00
2019-06-13 03:06:05 +02:00
// Loki : Archive all our sessions
2019-05-22 05:09:01 +02:00
// Ref : SignalServiceKit / Loki / Docs / SessionReset . md
2019-12-09 06:27:00 +01:00
[ self . primaryStorage archiveAllSessionsForContact : hexEncodedPublicKey protocolContext : transaction ] ;
2019-05-17 02:11:06 +02:00
2019-05-22 05:09:01 +02:00
// Loki : Set our session reset state
2020-02-17 01:24:16 +01:00
thread . sessionResetStatus = LKSessionResetStatusRequestReceived ;
2019-05-17 02:11:06 +02:00
[ thread saveWithTransaction : transaction ] ;
2019-05-22 05:09:01 +02:00
// Loki : Send an empty message to trigger the session reset code for both parties
2019-05-27 05:11:25 +02:00
LKEphemeralMessage * emptyMessage = [ [ LKEphemeralMessage alloc ] initInThread : thread ] ;
2019-05-17 02:11:06 +02:00
[ self . messageSenderJobQueue addMessage : emptyMessage transaction : transaction ] ;
2019-12-09 06:27:00 +01:00
NSLog ( @ "[Loki] Session reset received from %@." , hexEncodedPublicKey ) ;
2015-12-07 03:31:43 +01:00
}
2018-08-01 16:45:21 +02:00
- ( void ) handleExpirationTimerUpdateMessageWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-07-29 21:33:25 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2017-10-03 19:41:48 +02:00
TSThread * _Nullable thread = [ self threadForEnvelope : envelope dataMessage : dataMessage transaction : transaction ] ;
if ( ! thread ) {
2018-08-27 18:51:32 +02:00
OWSFailDebug ( @ "ignoring expiring messages update for unknown group." ) ;
2017-10-03 19:41:48 +02:00
return ;
}
2016-10-05 17:42:44 +02:00
OWSDisappearingMessagesConfiguration * disappearingMessagesConfiguration ;
if ( dataMessage . hasExpireTimer && dataMessage . expireTimer > 0 ) {
2018-08-27 18:55:37 +02:00
OWSLogInfo (
@ "Expiring messages duration turned to %u for thread %@" , ( unsigned int ) dataMessage . expireTimer , thread ) ;
2016-10-05 17:42:44 +02:00
disappearingMessagesConfiguration =
[ [ OWSDisappearingMessagesConfiguration alloc ] initWithThreadId : thread . uniqueId
enabled : YES
durationSeconds : dataMessage . expireTimer ] ;
} else {
2018-08-27 18:51:32 +02:00
OWSLogInfo ( @ "Expiring messages have been turned off for thread %@" , thread ) ;
2016-10-05 17:42:44 +02:00
disappearingMessagesConfiguration = [ [ OWSDisappearingMessagesConfiguration alloc ]
initWithThreadId : thread . uniqueId
enabled : NO
durationSeconds : OWSDisappearingMessagesConfigurationDefaultExpirationDuration ] ;
}
2018-09-06 19:01:24 +02:00
OWSAssertDebug ( disappearingMessagesConfiguration ) ;
2017-09-13 21:35:33 +02:00
[ disappearingMessagesConfiguration saveWithTransaction : transaction ] ;
2019-12-13 01:23:45 +01:00
NSString * name = [ dataMessage . profile displayName ] ? : [ self . contactsManager displayNameForPhoneIdentifier : envelope . source transaction : transaction ] ;
2018-10-03 23:41:43 +02:00
// MJK TODO - safe to remove senderTimestamp
2016-10-05 17:42:44 +02:00
OWSDisappearingConfigurationUpdateInfoMessage * message =
2018-09-20 22:10:35 +02:00
[ [ OWSDisappearingConfigurationUpdateInfoMessage alloc ] initWithTimestamp : [ NSDate ows_millisecondTimeStamp ]
thread : thread
configuration : disappearingMessagesConfiguration
createdByRemoteName : name
createdInExistingGroup : NO ] ;
2017-09-13 21:35:33 +02:00
[ message saveWithTransaction : transaction ] ;
2015-12-07 03:31:43 +01:00
}
2018-08-01 16:45:21 +02:00
- ( void ) handleProfileKeyMessageWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-08-28 23:00:55 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
2017-09-13 21:35:33 +02:00
NSString * recipientId = envelope . source ;
2017-08-28 23:00:55 +02:00
if ( ! dataMessage . hasProfileKey ) {
2018-08-27 18:55:37 +02:00
OWSFailDebug ( @ "received profile key message without profile key from: %@" , envelopeAddress ( envelope ) ) ;
2017-08-28 23:00:55 +02:00
return ;
}
NSData * profileKey = dataMessage . profileKey ;
if ( profileKey . length ! = kAES256_KeyByteLength ) {
2018-09-28 16:56:53 +02:00
OWSFailDebug ( @ "received profile key of unexpected length: %lu, from: %@" ,
2017-08-28 23:00:55 +02:00
( unsigned long ) profileKey . length ,
2017-09-13 21:35:33 +02:00
envelopeAddress ( envelope ) ) ;
2017-08-28 23:00:55 +02:00
return ;
}
2019-11-29 00:18:04 +01:00
if ( dataMessage . profile = = nil ) {
OWSFailDebug ( @ "received profile key message without loki profile attached from: %@" , envelopeAddress ( envelope ) ) ;
return ;
}
2017-08-28 23:00:55 +02:00
2018-09-17 15:27:58 +02:00
id < ProfileManagerProtocol > profileManager = SSKEnvironment . shared . profileManager ;
2019-11-29 00:18:04 +01:00
[ profileManager setProfileKeyData : profileKey forRecipientId : recipientId avatarURL : dataMessage . profile . profilePicture ] ;
2017-08-28 23:00:55 +02:00
}
2019-11-20 06:27:34 +01:00
- ( void ) handleUnlinkDeviceMessageWithEnvelope : ( SSKProtoEnvelope * ) envelope dataMessage : ( SSKProtoDataMessage * ) dataMessage transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
NSString * senderHexEncodedPublicKey = envelope . source ;
NSString * userHexEncodedPublicKey = OWSIdentityManager . sharedManager . identityKeyPair . hexEncodedPublicKey ;
NSString * masterHexEncodedPublicKey = [ LKDatabaseUtilities getMasterHexEncodedPublicKeyFor : userHexEncodedPublicKey in : transaction ] ;
if ( ! [ masterHexEncodedPublicKey isEqual : senderHexEncodedPublicKey ] ) { return ; }
NSSet < LKDeviceLink * > * deviceLinks = [ LKDatabaseUtilities getDeviceLinksFor : senderHexEncodedPublicKey in : transaction ] ;
if ( ! [ deviceLinks contains : ^ BOOL ( LKDeviceLink * deviceLink ) {
return [ deviceLink . master . hexEncodedPublicKey isEqual : senderHexEncodedPublicKey ] && [ deviceLink . slave . hexEncodedPublicKey isEqual : userHexEncodedPublicKey ] ;
} ] ) {
return ;
}
2020-02-10 04:40:53 +01:00
[ LKFileServerAPI getDeviceLinksAssociatedWith : userHexEncodedPublicKey ] . thenOn ( dispatch_get _main _queue ( ) , ^ ( NSSet < LKDeviceLink * > * deviceLinks ) {
2019-11-21 00:10:34 +01:00
if ( [ deviceLinks contains : ^ BOOL ( LKDeviceLink * deviceLink ) {
2019-11-20 06:27:34 +01:00
return [ deviceLink . master . hexEncodedPublicKey isEqual : senderHexEncodedPublicKey ] && [ deviceLink . slave . hexEncodedPublicKey isEqual : userHexEncodedPublicKey ] ;
} ] ) {
2019-11-20 22:22:36 +01:00
[ NSUserDefaults . standardUserDefaults setBool : YES forKey : @ "wasUnlinked" ] ;
2019-11-21 00:10:34 +01:00
[ NSNotificationCenter . defaultCenter postNotificationName : NSNotification . dataNukeRequested object : nil ] ;
2019-11-20 06:27:34 +01:00
}
} ) ;
}
2018-08-01 16:45:21 +02:00
- ( void ) handleReceivedTextMessageWithEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-07-29 21:33:25 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
2017-09-13 21:35:33 +02:00
2018-12-02 23:30:31 +01:00
[ self handleReceivedEnvelope : envelope
withDataMessage : dataMessage
wasReceivedByUD : wasReceivedByUD
transaction : transaction ] ;
2015-12-07 03:31:43 +01:00
}
2018-08-01 16:45:21 +02:00
- ( void ) handleGroupInfoRequest : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2017-05-10 16:05:01 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return ;
}
if ( dataMessage . group . type ! = SSKProtoGroupContextTypeRequestInfo ) {
OWSFailDebug ( @ "Unexpected group message type." ) ;
return ;
}
2017-05-10 16:05:01 +02:00
2018-08-08 19:41:12 +02:00
NSData * groupId = dataMessage . group ? dataMessage . group . id : nil ;
2017-05-10 16:05:01 +02:00
if ( ! groupId ) {
2018-08-27 16:29:51 +02:00
OWSFailDebug ( @ "Group info request is missing group id." ) ;
2017-05-10 16:05:01 +02:00
return ;
}
2018-08-30 16:31:01 +02:00
OWSLogInfo ( @ "Received 'Request Group Info' message for group: %@ from: %@" , groupId , envelope . source ) ;
2017-05-10 16:05:01 +02:00
2017-10-03 19:41:48 +02:00
TSGroupThread * _Nullable gThread = [ TSGroupThread threadWithGroupId : dataMessage . group . id transaction : transaction ] ;
2017-09-13 21:35:33 +02:00
if ( ! gThread ) {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "Unknown group: %@" , groupId ) ;
2017-09-13 21:35:33 +02:00
return ;
}
2017-05-12 18:39:36 +02:00
2017-10-04 16:19:19 +02:00
// Ensure sender is in the group .
2020-02-17 00:59:25 +01:00
if ( ! [ gThread isUserInGroup : envelope . source transaction : transaction ] ) {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "Ignoring 'Request Group Info' message for non-member of group. %@ not in %@" ,
2017-09-13 21:35:33 +02:00
envelope . source ,
gThread . groupModel . groupMemberIds ) ;
2017-10-04 16:19:19 +02:00
return ;
}
// Ensure we are in the group .
2020-01-30 05:51:46 +01:00
if ( ! [ gThread isLocalUserInGroupWithTransaction : transaction ] ) {
2018-08-27 18:51:32 +02:00
OWSLogWarn ( @ "Ignoring 'Request Group Info' message for group we no longer belong to." ) ;
2017-10-04 16:19:19 +02:00
return ;
2017-09-13 21:35:33 +02:00
}
2017-05-10 16:05:01 +02:00
2017-09-13 21:35:33 +02:00
NSString * updateGroupInfo =
[ gThread . groupModel getInfoStringAboutUpdateTo : gThread . groupModel contactsManager : self . contactsManager ] ;
2018-06-13 22:44:22 +02:00
uint32_t expiresInSeconds = [ gThread disappearingMessagesDurationWithTransaction : transaction ] ;
TSOutgoingMessage * message = [ TSOutgoingMessage outgoingMessageInThread : gThread
2018-08-31 18:43:05 +02:00
groupMetaMessage : TSGroupMetaMessageUpdate
2018-06-13 22:44:22 +02:00
expiresInSeconds : expiresInSeconds ] ;
2017-09-13 21:35:33 +02:00
[ message updateWithCustomMessage : updateGroupInfo transaction : transaction ] ;
// Only send this group update to the requester .
2018-04-24 22:38:35 +02:00
[ message updateWithSendingToSingleGroupRecipient : envelope . source transaction : transaction ] ;
2017-09-13 21:35:33 +02:00
2018-10-20 19:51:48 +02:00
if ( gThread . groupModel . groupImage ) {
2019-01-07 15:57:19 +01:00
NSData * _Nullable data = UIImagePNGRepresentation ( gThread . groupModel . groupImage ) ;
OWSAssertDebug ( data ) ;
if ( data ) {
DataSource * _Nullable dataSource = [ DataSourceValue dataSourceWithData : data fileExtension : @ "png" ] ;
[ self . messageSenderJobQueue addMediaMessage : message
dataSource : dataSource
contentType : OWSMimeTypeImagePng
sourceFilename : nil
caption : nil
albumMessageId : nil
isTemporaryAttachment : YES ] ;
}
2018-10-20 19:51:48 +02:00
} else {
[ self . messageSenderJobQueue addMessage : message transaction : transaction ] ;
}
2017-05-10 16:05:01 +02:00
}
2018-08-01 16:45:21 +02:00
- ( TSIncomingMessage * _Nullable ) handleReceivedEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
withDataMessage : ( SSKProtoDataMessage * ) dataMessage
2018-12-02 23:30:31 +01:00
wasReceivedByUD : ( BOOL ) wasReceivedByUD
2017-09-13 21:35:33 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-07-29 21:33:25 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return nil ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return nil ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return nil ;
}
2017-09-13 21:35:33 +02:00
2016-10-05 17:42:44 +02:00
uint64_t timestamp = envelope . timestamp ;
2016-08-22 22:09:58 +02:00
NSString * body = dataMessage . body ;
2018-08-08 19:41:12 +02:00
NSData * groupId = dataMessage . group ? dataMessage . group . id : nil ;
2018-07-13 20:03:28 +02:00
OWSContact * _Nullable contact = [ OWSContacts contactForDataMessage : dataMessage transaction : transaction ] ;
2018-10-02 20:34:26 +02:00
NSNumber * _Nullable serverTimestamp = ( envelope . hasServerTimestamp ? @ ( envelope . serverTimestamp ) : nil ) ;
2015-12-07 03:31:43 +01:00
2018-08-01 23:13:01 +02:00
if ( dataMessage . group . type = = SSKProtoGroupContextTypeRequestInfo ) {
2017-09-13 21:35:33 +02:00
[ self handleGroupInfoRequest : envelope dataMessage : dataMessage transaction : transaction ] ;
2017-05-10 16:05:01 +02:00
return nil ;
}
2020-02-15 00:01:21 +01:00
// The envelope source is set during UD decryption .
2020-02-19 01:11:07 +01:00
if ( [ ECKeyPair isValidHexEncodedPublicKeyWithCandidate : envelope . source ] && dataMessage . publicChatInfo = = nil ) { // Handled in LokiPublicChatPoller for open group messages
2020-02-14 06:32:47 +01:00
dispatch_semaphore _t semaphore = dispatch_semaphore _create ( 0 ) ;
[ [ LKAPI getDestinationsFor : envelope . source inTransaction : transaction ] . ensureOn ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ ( ) {
dispatch_semaphore _signal ( semaphore ) ;
} ) . catchOn ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT , 0 ) , ^ ( NSError * error ) {
dispatch_semaphore _signal ( semaphore ) ;
} ) retainUntilComplete ] ;
2020-02-25 10:32:05 +01:00
dispatch_semaphore _wait ( semaphore , dispatch_time ( DISPATCH_TIME _NOW , 10 * NSEC_PER _SEC ) ) ;
2020-02-14 06:32:47 +01:00
}
2017-10-03 19:41:48 +02:00
if ( groupId . length > 0 ) {
NSMutableSet * newMemberIds = [ NSMutableSet setWithArray : dataMessage . group . members ] ;
2020-01-17 04:13:02 +01:00
NSMutableSet * removedMemberIds = [ NSMutableSet new ] ;
2020-01-29 04:58:28 +01:00
for ( NSString * recipientId in newMemberIds ) {
if ( ! [ ECKeyPair isValidHexEncodedPublicKeyWithCandidate : recipientId ] ) {
OWSLogVerbose (
@ "incoming group update has invalid group member: %@" , [ self descriptionForEnvelope : envelope ] ) ;
OWSFailDebug ( @ "incoming group update has invalid group member" ) ;
return nil ;
}
}
2020-02-04 04:24:39 +01:00
NSString * hexEncodedPublicKey = ( [ LKDatabaseUtilities getMasterHexEncodedPublicKeyFor : envelope . source in : transaction ] ? : envelope . source ) ;
2017-10-03 19:41:48 +02:00
// Group messages create the group if it doesn ' t already exist .
//
// We distinguish between the old group state ( if any ) and the new group state .
TSGroupThread * _Nullable oldGroupThread = [ TSGroupThread threadWithGroupId : groupId transaction : transaction ] ;
if ( oldGroupThread ) {
2020-02-15 00:01:21 +01:00
// Loki : Determine removed members
2020-01-22 04:41:34 +01:00
removedMemberIds = [ NSMutableSet setWithArray : oldGroupThread . groupModel . groupMemberIds ] ;
[ removedMemberIds minusSet : newMemberIds ] ;
2020-02-04 04:24:39 +01:00
[ removedMemberIds removeObject : hexEncodedPublicKey ] ;
2017-10-03 19:41:48 +02:00
}
2017-09-13 21:35:33 +02:00
2019-11-29 00:18:04 +01:00
// Only set the display name here , the logic for updating profile pictures is handled when we ' re setting profile key
2020-01-20 01:32:07 +01:00
[ self handleProfileNameUpdateIfNeeded : dataMessage recipientId : hexEncodedPublicKey transaction : transaction ] ;
2019-11-18 05:59:50 +01:00
2017-09-13 21:35:33 +02:00
switch ( dataMessage . group . type ) {
2018-08-01 23:13:01 +02:00
case SSKProtoGroupContextTypeUpdate : {
2020-02-28 03:58:45 +01:00
if ( oldGroupThread && ! [ oldGroupThread isUserAdminInGroup : hexEncodedPublicKey transaction : transaction ] ) {
2020-01-29 04:58:28 +01:00
[ LKLogger print : [ NSString stringWithFormat : @ "[Loki] Received a group update from a non-admin user for %@; ignoring." , [ LKGroupUtilities getEncodedGroupID : groupId ] ] ] ;
2020-01-22 04:41:34 +01:00
return nil ;
}
2017-10-03 19:41:48 +02:00
// Ensures that the thread exists but doesn ' t update it .
TSGroupThread * newGroupThread =
2020-01-10 00:52:47 +01:00
[ TSGroupThread getOrCreateThreadWithGroupId : groupId groupType : oldGroupThread . groupModel . groupType transaction : transaction ] ;
2017-10-03 19:41:48 +02:00
TSGroupModel * newGroupModel = [ [ TSGroupModel alloc ] initWithTitle : dataMessage . group . name
2018-02-13 07:10:29 +01:00
memberIds : newMemberIds . allObjects
2017-10-04 16:06:38 +02:00
image : oldGroupThread . groupModel . groupImage
2020-01-10 00:52:47 +01:00
groupId : dataMessage . group . id
2020-01-22 04:41:34 +01:00
groupType : oldGroupThread . groupModel . groupType
adminIds : dataMessage . group . admins ] ;
2020-01-14 04:58:22 +01:00
newGroupModel . removedMembers = removedMemberIds ;
2017-10-03 19:41:48 +02:00
NSString * updateGroupInfo = [ newGroupThread . groupModel getInfoStringAboutUpdateTo : newGroupModel
contactsManager : self . contactsManager ] ;
newGroupThread . groupModel = newGroupModel ;
[ newGroupThread saveWithTransaction : transaction ] ;
2020-01-17 00:38:16 +01:00
2020-01-29 04:58:28 +01:00
// Loki : Try to establish sessions with all members when a group is created or updated
2020-01-17 00:38:16 +01:00
[ self establishSessionsWithMembersIfNeeded : newMemberIds . allObjects forThread : newGroupThread transaction : transaction ] ;
2017-10-03 19:41:48 +02:00
2018-10-03 23:41:43 +02:00
[ [ OWSDisappearingMessagesJob sharedJob ] becomeConsistentWithDisappearingDuration : dataMessage . expireTimer
thread : newGroupThread
createdByRemoteRecipientId : nil
2019-01-04 18:57:13 +01:00
createdInExistingGroup : YES
2018-10-03 23:41:43 +02:00
transaction : transaction ] ;
// MJK TODO - should be safe to remove senderTimestamp
TSInfoMessage * infoMessage = [ [ TSInfoMessage alloc ] initWithTimestamp : [ NSDate ows_millisecondTimeStamp ]
2018-09-20 22:10:35 +02:00
inThread : newGroupThread
messageType : TSInfoMessageTypeGroupUpdate
customMessage : updateGroupInfo ] ;
2018-09-20 19:19:12 +02:00
[ infoMessage saveWithTransaction : transaction ] ;
2018-06-14 16:08:38 +02:00
2017-10-04 16:06:38 +02:00
return nil ;
2017-09-13 21:35:33 +02:00
}
2018-08-01 23:13:01 +02:00
case SSKProtoGroupContextTypeQuit : {
2017-10-03 19:41:48 +02:00
if ( ! oldGroupThread ) {
2018-09-18 22:44:31 +02:00
OWSLogWarn ( @ "ignoring quit group message from unknown group." ) ;
2017-10-03 19:41:48 +02:00
return nil ;
}
2020-02-04 07:04:00 +01:00
newMemberIds = [ NSMutableSet setWithArray : oldGroupThread . groupModel . groupMemberIds ] ;
2020-02-04 04:24:39 +01:00
[ newMemberIds removeObject : hexEncodedPublicKey ] ;
2017-10-03 19:41:48 +02:00
oldGroupThread . groupModel . groupMemberIds = [ newMemberIds . allObjects mutableCopy ] ;
[ oldGroupThread saveWithTransaction : transaction ] ;
2017-09-13 21:35:33 +02:00
2018-10-26 19:21:08 +02:00
NSString * nameString =
2020-02-04 04:24:39 +01:00
[ self . contactsManager displayNameForPhoneIdentifier : hexEncodedPublicKey transaction : transaction ] ;
2017-09-13 21:35:33 +02:00
NSString * updateGroupInfo =
[ NSString stringWithFormat : NSLocalizedString ( @ "GROUP_MEMBER_LEFT" , @ "" ) , nameString ] ;
2018-10-03 23:41:43 +02:00
// MJK TODO - should be safe to remove senderTimestamp
2018-09-20 22:10:35 +02:00
[ [ [ TSInfoMessage alloc ] initWithTimestamp : [ NSDate ows_millisecondTimeStamp ]
inThread : oldGroupThread
messageType : TSInfoMessageTypeGroupUpdate
customMessage : updateGroupInfo ] saveWithTransaction : transaction ] ;
2017-10-04 16:06:38 +02:00
return nil ;
2017-09-13 21:35:33 +02:00
}
2018-08-01 23:13:01 +02:00
case SSKProtoGroupContextTypeDeliver : {
2017-10-03 19:41:48 +02:00
if ( ! oldGroupThread ) {
2018-08-27 18:51:32 +02:00
OWSFailDebug ( @ "ignoring deliver group message from unknown group." ) ;
2017-10-03 19:41:48 +02:00
return nil ;
}
2018-10-03 23:41:43 +02:00
[ [ OWSDisappearingMessagesJob sharedJob ] becomeConsistentWithDisappearingDuration : dataMessage . expireTimer
thread : oldGroupThread
2020-02-04 04:24:39 +01:00
createdByRemoteRecipientId : hexEncodedPublicKey
2019-01-04 18:57:13 +01:00
createdInExistingGroup : NO
2018-10-03 23:41:43 +02:00
transaction : transaction ] ;
2018-04-07 21:26:22 +02:00
TSQuotedMessage * _Nullable quotedMessage = [ TSQuotedMessage quotedMessageForDataMessage : dataMessage
thread : oldGroupThread
transaction : transaction ] ;
2018-02-07 18:44:09 +01:00
2019-01-15 16:36:21 +01:00
NSError * linkPreviewError ;
2019-01-14 17:00:24 +01:00
OWSLinkPreview * _Nullable linkPreview =
2019-01-14 22:44:18 +01:00
[ OWSLinkPreview buildValidatedLinkPreviewWithDataMessage : dataMessage
body : body
2019-01-15 16:36:21 +01:00
transaction : transaction
error : & linkPreviewError ] ;
if ( linkPreviewError && ! [ OWSLinkPreview isNoPreviewError : linkPreviewError ] ) {
OWSLogError ( @ "linkPreviewError: %@" , linkPreviewError ) ;
}
2019-01-14 17:00:24 +01:00
2018-08-27 18:55:37 +02:00
OWSLogDebug ( @ "incoming message from: %@ for group: %@ with timestamp: %lu" ,
2017-10-03 19:41:48 +02:00
envelopeAddress ( envelope ) ,
groupId ,
( unsigned long ) timestamp ) ;
2019-08-28 03:09:28 +02:00
2018-10-03 23:41:43 +02:00
// Legit usage of senderTimestamp when creating an incoming group message record
2017-10-04 16:06:38 +02:00
TSIncomingMessage * incomingMessage =
2018-09-20 22:10:35 +02:00
[ [ TSIncomingMessage alloc ] initIncomingMessageWithTimestamp : timestamp
inThread : oldGroupThread
2020-02-04 04:24:39 +01:00
authorId : hexEncodedPublicKey
2018-09-20 22:10:35 +02:00
sourceDeviceId : envelope . sourceDevice
messageBody : body
2018-11-07 23:42:40 +01:00
attachmentIds : @ [ ]
2018-09-20 22:10:35 +02:00
expiresInSeconds : dataMessage . expireTimer
quotedMessage : quotedMessage
2018-10-02 20:34:26 +02:00
contactShare : contact
2019-01-14 17:00:24 +01:00
linkPreview : linkPreview
2018-10-10 16:17:58 +02:00
serverTimestamp : serverTimestamp
wasReceivedByUD : wasReceivedByUD ] ;
2019-05-27 07:06:54 +02:00
2019-10-31 06:52:22 +01:00
// Loki : Parse Loki specific properties if needed
2019-05-27 07:06:54 +02:00
if ( envelope . isPtpMessage ) { incomingMessage . isP2P = YES ; }
2019-10-31 06:52:22 +01:00
if ( dataMessage . publicChatInfo ! = nil && dataMessage . publicChatInfo . hasServerID ) { incomingMessage . groupChatServerID = dataMessage . publicChatInfo . serverID ; }
2018-02-07 18:44:09 +01:00
2018-11-07 23:49:25 +01:00
NSArray < TSAttachmentPointer * > * attachmentPointers =
[ TSAttachmentPointer attachmentPointersFromProtos : dataMessage . attachments
albumMessage : incomingMessage ] ;
for ( TSAttachmentPointer * pointer in attachmentPointers ) {
[ pointer saveWithTransaction : transaction ] ;
[ incomingMessage . attachmentIds addObject : pointer . uniqueId ] ;
}
2019-09-09 08:23:40 +02:00
2019-09-10 05:26:58 +02:00
// Loki : Don ' t process friend requests in group chats
2018-11-07 23:49:25 +01:00
if ( body . length = = 0 && attachmentPointers . count < 1 && ! contact ) {
2020-02-15 00:01:21 +01:00
OWSLogWarn ( @ "Ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu." ,
2020-02-04 04:24:39 +01:00
hexEncodedPublicKey ,
2018-11-07 23:49:25 +01:00
groupId ,
( unsigned long ) timestamp ) ;
return nil ;
}
2019-10-09 02:16:10 +02:00
2019-10-08 06:02:03 +02:00
// Loki : Cache the user hex encoded public key ( for mentions )
2019-11-13 03:23:55 +01:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ OWSPrimaryStorage . sharedManager . dbReadConnection readWithBlock : ^ ( YapDatabaseReadTransaction * transaction ) {
[ LKAPI populateUserHexEncodedPublicKeyCacheIfNeededFor : oldGroupThread . uniqueId in : transaction ] ;
[ LKAPI cache : incomingMessage . authorId for : oldGroupThread . uniqueId ] ;
} ] ;
2019-11-13 03:12:25 +01:00
} ) ;
2019-10-08 06:02:03 +02:00
2017-10-04 16:06:38 +02:00
[ self finalizeIncomingMessage : incomingMessage
thread : oldGroupThread
2019-11-06 05:45:41 +01:00
masterThread : oldGroupThread
2017-10-04 16:06:38 +02:00
envelope : envelope
transaction : transaction ] ;
2019-08-30 07:57:34 +02:00
2019-10-08 06:02:03 +02:00
// Loki : Map the message ID to the message server ID if needed
2019-08-30 07:57:34 +02:00
if ( dataMessage . publicChatInfo ! = nil && dataMessage . publicChatInfo . hasServerID ) {
[ self . primaryStorage setIDForMessageWithServerID : dataMessage . publicChatInfo . serverID to : incomingMessage . uniqueId in : transaction ] ;
}
2019-09-05 08:56:50 +02:00
2017-10-04 16:06:38 +02:00
return incomingMessage ;
2017-09-13 21:35:33 +02:00
}
default : {
2020-02-15 00:01:21 +01:00
OWSLogWarn ( @ "Ignoring unknown group message type: %d." , ( int ) dataMessage . group . type ) ;
2017-10-03 19:41:48 +02:00
return nil ;
2017-09-13 21:35:33 +02:00
}
}
} else {
2019-10-04 06:52:59 +02:00
2020-02-15 00:01:21 +01:00
// Loki : A message from a slave device should appear as if it came from the master device ; the underlying
// friend request logic , however , should still be specific to the slave device .
2019-11-06 06:09:20 +01:00
2019-11-06 05:45:41 +01:00
// Loki : Get the master hex encoded public key and thread
NSString * hexEncodedPublicKey = envelope . source ;
NSString * masterHexEncodedPublicKey = ( [ LKDatabaseUtilities getMasterHexEncodedPublicKeyFor : envelope . source in : transaction ] ? : envelope . source ) ;
TSContactThread * thread = [ TSContactThread getOrCreateThreadWithContactId : hexEncodedPublicKey transaction : transaction ] ;
TSContactThread * masterThread = [ TSContactThread getOrCreateThreadWithContactId : masterHexEncodedPublicKey transaction : transaction ] ;
2017-10-04 16:06:38 +02:00
2020-02-15 00:01:21 +01:00
OWSLogDebug ( @ "Incoming message from: %@ with timestamp: %lu." , hexEncodedPublicKey , ( unsigned long ) timestamp ) ;
2019-11-06 05:45:41 +01:00
2018-10-03 23:41:43 +02:00
[ [ OWSDisappearingMessagesJob sharedJob ] becomeConsistentWithDisappearingDuration : dataMessage . expireTimer
2019-11-06 05:45:41 +01:00
thread : masterThread
2019-10-04 06:03:38 +02:00
createdByRemoteRecipientId : hexEncodedPublicKey
2018-10-03 23:41:43 +02:00
createdInExistingGroup : NO
transaction : transaction ] ;
2018-04-07 21:26:22 +02:00
TSQuotedMessage * _Nullable quotedMessage = [ TSQuotedMessage quotedMessageForDataMessage : dataMessage
2019-11-06 05:45:41 +01:00
thread : masterThread
2018-04-07 21:26:22 +02:00
transaction : transaction ] ;
2018-02-07 18:44:09 +01:00
2019-01-15 16:36:21 +01:00
NSError * linkPreviewError ;
2019-01-14 17:00:24 +01:00
OWSLinkPreview * _Nullable linkPreview =
2019-01-15 16:36:21 +01:00
[ OWSLinkPreview buildValidatedLinkPreviewWithDataMessage : dataMessage
body : body
transaction : transaction
error : & linkPreviewError ] ;
if ( linkPreviewError && ! [ OWSLinkPreview isNoPreviewError : linkPreviewError ] ) {
OWSLogError ( @ "linkPreviewError: %@" , linkPreviewError ) ;
}
2019-01-14 17:00:24 +01:00
2018-10-03 23:41:43 +02:00
// Legit usage of senderTimestamp when creating incoming message from received envelope
2018-02-07 18:44:09 +01:00
TSIncomingMessage * incomingMessage =
2018-09-20 22:10:35 +02:00
[ [ TSIncomingMessage alloc ] initIncomingMessageWithTimestamp : timestamp
2019-11-06 05:45:41 +01:00
inThread : masterThread
authorId : masterThread . contactIdentifier
2018-09-20 22:10:35 +02:00
sourceDeviceId : envelope . sourceDevice
messageBody : body
2018-11-07 23:42:40 +01:00
attachmentIds : @ [ ]
2018-09-20 22:10:35 +02:00
expiresInSeconds : dataMessage . expireTimer
quotedMessage : quotedMessage
2018-10-02 20:34:26 +02:00
contactShare : contact
2019-01-14 17:00:24 +01:00
linkPreview : linkPreview
2018-10-10 16:17:58 +02:00
serverTimestamp : serverTimestamp
wasReceivedByUD : wasReceivedByUD ] ;
2019-10-17 07:39:22 +02:00
2019-09-12 03:22:42 +02:00
NSString * rawDisplayName = dataMessage . profile . displayName ;
2019-10-17 07:39:22 +02:00
NSString * displayName = nil ;
2019-09-12 03:22:42 +02:00
if ( rawDisplayName ! = nil && rawDisplayName . length > 0 ) {
2019-10-17 07:39:22 +02:00
displayName = [ NSString stringWithFormat : @ "%@ (...%@)" , rawDisplayName , [ incomingMessage . authorId substringFromIndex : incomingMessage . authorId . length - 8 ] ] ;
}
2019-11-29 00:18:04 +01:00
[ self . profileManager updateProfileForContactWithID : thread . contactIdentifier displayName : displayName with : transaction ] ;
[ self handleProfileKeyUpdateIfNeeded : dataMessage recipientId : thread . contactIdentifier ] ;
2019-11-18 05:59:50 +01:00
2019-10-31 06:52:22 +01:00
// Loki : Parse Loki specific properties if needed
2019-05-27 07:06:54 +02:00
if ( envelope . isPtpMessage ) { incomingMessage . isP2P = YES ; }
2018-11-07 23:49:25 +01:00
NSArray < TSAttachmentPointer * > * attachmentPointers =
[ TSAttachmentPointer attachmentPointersFromProtos : dataMessage . attachments albumMessage : incomingMessage ] ;
for ( TSAttachmentPointer * pointer in attachmentPointers ) {
[ pointer saveWithTransaction : transaction ] ;
[ incomingMessage . attachmentIds addObject : pointer . uniqueId ] ;
}
2019-05-17 03:39:54 +02:00
// Loki : Do this before the check below
2019-10-31 04:24:53 +01:00
[ self handleFriendRequestMessageIfNeededWithEnvelope : envelope data : dataMessage message : incomingMessage thread : thread transaction : transaction ] ;
2019-05-17 03:39:54 +02:00
2018-11-07 23:49:25 +01:00
if ( body . length = = 0 && attachmentPointers . count < 1 && ! contact ) {
2020-02-15 00:01:21 +01:00
OWSLogWarn ( @ "Ignoring empty incoming message from: %@ with timestamp: %lu." ,
2019-10-04 06:03:38 +02:00
hexEncodedPublicKey ,
2018-11-07 23:49:25 +01:00
( unsigned long ) timestamp ) ;
return nil ;
}
2019-05-27 01:50:37 +02:00
2019-09-18 03:09:09 +02:00
// Loki : If we received a message from a contact in the last 2 minutes that wasn ' t P2P , then we need to ping them .
// We assume this occurred because they don ' t have our P2P details .
2019-10-04 06:03:38 +02:00
if ( ! envelope . isPtpMessage && hexEncodedPublicKey ! = nil ) {
2019-05-27 01:50:37 +02:00
uint64_t timestamp = envelope . timestamp ;
uint64_t now = NSDate . ows_millisecondTimeStamp ;
uint64_t ageInSeconds = ( now - timestamp ) / 1000 ;
2019-10-04 06:03:38 +02:00
if ( ageInSeconds <= 120 ) { [ LKP2PAPI pingContact : hexEncodedPublicKey ] ; }
2019-05-27 01:50:37 +02:00
}
2018-11-07 23:49:25 +01:00
2017-10-04 16:06:38 +02:00
[ self finalizeIncomingMessage : incomingMessage
thread : thread
2019-11-06 05:45:41 +01:00
masterThread : thread
2017-10-04 16:06:38 +02:00
envelope : envelope
transaction : transaction ] ;
2019-09-09 08:51:18 +02:00
2017-10-04 16:06:38 +02:00
return incomingMessage ;
2017-09-13 21:35:33 +02:00
}
2017-10-04 16:06:38 +02:00
}
2015-12-07 03:31:43 +01:00
2019-12-01 23:49:16 +01:00
- ( void ) handleProfileNameUpdateIfNeeded : ( SSKProtoDataMessage * ) dataMessage recipientId : ( NSString * ) recipientId transaction : ( YapDatabaseReadWriteTransaction * ) transaction {
2019-12-02 01:01:07 +01:00
if ( dataMessage ! = nil && dataMessage . profile ! = nil ) {
2019-12-01 23:49:16 +01:00
[ self . profileManager updateProfileForContactWithID : recipientId displayName : dataMessage . profile . displayName with : transaction ] ;
}
}
2019-11-29 00:18:04 +01:00
- ( void ) handleProfileKeyUpdateIfNeeded : ( SSKProtoDataMessage * ) dataMessage recipientId : ( NSString * ) recipientId {
2019-12-02 01:01:07 +01:00
if ( dataMessage ! = nil && [ dataMessage hasProfileKey ] ) {
2019-11-29 00:18:04 +01:00
NSData * profileKey = [ dataMessage profileKey ] ;
NSString * url = dataMessage . profile ! = nil ? dataMessage . profile . profilePicture : nil ;
if ( profileKey . length = = kAES256_KeyByteLength ) {
[ self . profileManager setProfileKeyData : profileKey forRecipientId : recipientId avatarURL : url ] ;
} else {
2020-02-15 00:01:21 +01:00
OWSFailDebug ( @ "Unexpected profile key length:%lu on message from:%@" , ( unsigned long ) profileKey . length , recipientId ) ;
2019-11-29 00:18:04 +01:00
}
}
}
2020-01-30 01:12:11 +01:00
- ( void ) establishSessionsWithMembersIfNeeded : ( NSArray * ) members forThread : ( TSGroupThread * ) thread transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2020-01-17 00:38:16 +01:00
{
NSString * userHexEncodedPublicKey = OWSIdentityManager . sharedManager . identityKeyPair . hexEncodedPublicKey ;
for ( NSString * member in members ) {
if ( [ member isEqualToString : userHexEncodedPublicKey ] ) { continue ; }
2020-01-30 01:12:11 +01:00
BOOL hasSession = [ self . primaryStorage containsSession : member deviceId : 1 protocolContext : transaction ] ;
2020-01-29 04:58:28 +01:00
if ( hasSession ) { continue ; }
2020-01-30 01:12:11 +01:00
TSContactThread * contactThread = [ TSContactThread getOrCreateThreadWithContactId : member transaction : transaction ] ;
LKSessionRequestMessage * message = [ [ LKSessionRequestMessage alloc ] initWithThread : contactThread ] ;
2020-01-29 04:58:28 +01:00
[ self . messageSenderJobQueue addMessage : message transaction : transaction ] ;
2020-01-17 00:38:16 +01:00
}
}
2019-11-07 00:19:22 +01:00
- ( BOOL ) canFriendRequestBeAutoAcceptedForThread : ( TSContactThread * ) thread transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
2019-11-07 01:08:32 +01:00
NSString * senderHexEncodedPublicKey = thread . contactIdentifier ;
2019-07-24 01:20:33 +02:00
if ( thread . hasCurrentUserSentFriendRequest ) {
// This can happen if Alice sent Bob a friend request , Bob declined , but then Bob changed his
// mind and sent a friend request to Alice . In this case we want Alice to auto - accept the request
// and send a friend request accepted message back to Bob . We don ' t check that sending the
// friend request accepted message succeeded . Even if it doesn ' t , the thread ' s current friend
// request status will be set to LKThreadFriendRequestStatusFriends for Alice making it possible
// for Alice to send messages to Bob . When Bob receives a message , his thread ' s friend request status
// will then be set to LKThreadFriendRequestStatusFriends . If we do check for a successful send
// before updating Alice ' s thread ' s friend request status to LKThreadFriendRequestStatusFriends ,
// we can end up in a deadlock where both users ' threads ' friend request statuses are
// LKThreadFriendRequestStatusRequestSent .
2019-11-07 00:19:22 +01:00
return YES ;
}
NSString * userHexEncodedPublicKey = OWSIdentityManager . sharedManager . identityKeyPair . hexEncodedPublicKey ;
2019-11-07 01:08:32 +01:00
NSSet < NSString * > * userLinkedDeviceHexEncodedPublicKeys = [ LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor : userHexEncodedPublicKey in : transaction ] ;
2019-11-07 00:19:22 +01:00
if ( [ userLinkedDeviceHexEncodedPublicKeys containsObject : senderHexEncodedPublicKey ] ) {
// Auto - accept any friend requests from the user ' s own linked devices
return YES ;
}
2019-11-07 01:08:32 +01:00
NSSet < TSContactThread * > * senderLinkedDeviceThreads = [ LKDatabaseUtilities getLinkedDeviceThreadsFor : senderHexEncodedPublicKey in : transaction ] ;
2019-11-07 01:59:11 +01:00
if ( [ senderLinkedDeviceThreads contains : ^ BOOL ( TSContactThread * thread ) {
2019-11-07 00:19:22 +01:00
return thread . isContactFriend ;
} ] ) {
// Auto - accept if the user is friends with any of the sender ' s linked devices .
return YES ;
}
return NO ;
}
- ( void ) handleFriendRequestMessageIfNeededWithEnvelope : ( SSKProtoEnvelope * ) envelope data : ( SSKProtoDataMessage * ) data message : ( TSIncomingMessage * ) message thread : ( TSContactThread * ) thread transaction : ( YapDatabaseReadWriteTransaction * ) transaction {
if ( envelope . isGroupChatMessage ) {
return NSLog ( @ "[Loki] Ignoring friend request in group chat." , @ "" ) ;
}
2020-02-15 00:01:21 +01:00
// The envelope type is set during UD decryption .
2019-11-07 00:19:22 +01:00
if ( envelope . type ! = SSKProtoEnvelopeTypeFriendRequest ) {
2020-02-14 01:03:25 +01:00
return NSLog ( @ "[Loki] Ignoring friend request logic for non friend request type envelope." ) ;
2019-11-07 00:19:22 +01:00
}
if ( [ self canFriendRequestBeAutoAcceptedForThread : thread transaction : transaction ] ) {
2019-05-24 08:25:25 +02:00
[ thread saveFriendRequestStatus : LKThreadFriendRequestStatusFriends withTransaction : transaction ] ;
2019-11-07 00:19:22 +01:00
__block TSOutgoingMessage * existingFriendRequestMessage ;
[ thread enumerateInteractionsWithTransaction : transaction usingBlock : ^ ( TSInteraction * interaction , YapDatabaseReadTransaction * transaction ) {
if ( [ interaction isKindOfClass : TSOutgoingMessage . class ] && ( ( TSOutgoingMessage * ) interaction ) . isFriendRequest ) {
existingFriendRequestMessage = ( TSOutgoingMessage * ) interaction ;
}
} ] ;
if ( existingFriendRequestMessage ! = nil ) {
2019-05-24 08:25:25 +02:00
[ existingFriendRequestMessage saveFriendRequestStatus : LKMessageFriendRequestStatusAccepted withTransaction : transaction ] ;
2019-05-21 01:53:10 +02:00
}
2019-09-24 06:20:22 +02:00
// The two lines below are equivalent to calling [ ThreadUtil enqueueFriendRequestAcceptanceMessageInThread : thread ]
2019-07-24 01:35:35 +02:00
LKEphemeralMessage * backgroundMessage = [ [ LKEphemeralMessage alloc ] initInThread : thread ] ;
[ self . messageSenderJobQueue addMessage : backgroundMessage transaction : transaction ] ;
2019-11-07 00:19:22 +01:00
} else if ( ! thread . isContactFriend ) {
// Checking that the sender of the message isn ' t already a friend is necessary because otherwise
// the following situation can occur : Alice and Bob are friends . Bob loses his database and his
// friend request status is reset to LKThreadFriendRequestStatusNone . Bob now sends Alice a friend
// request . Alice ' s thread ' s friend request status is reset to
// LKThreadFriendRequestStatusRequestReceived .
[ thread saveFriendRequestStatus : LKThreadFriendRequestStatusRequestReceived withTransaction : transaction ] ;
// Except for the message . friendRequestStatus = LKMessageFriendRequestStatusPending line below , all of this is to ensure that
// there ' s only ever one message with status LKMessageFriendRequestStatusPending in a thread ( where a thread is the combination
// of all threads belonging to the linked devices of a user ) .
NSString * senderID = ( ( TSIncomingMessage * ) message ) . authorId ;
2019-11-07 04:28:55 +01:00
NSSet < TSContactThread * > * linkedDeviceThreads = [ LKDatabaseUtilities getLinkedDeviceThreadsFor : senderID in : transaction ] ;
2019-11-07 01:08:32 +01:00
for ( TSContactThread * thread in linkedDeviceThreads ) {
2019-11-07 00:19:22 +01:00
[ thread enumerateInteractionsWithTransaction : transaction usingBlock : ^ ( TSInteraction * interaction , YapDatabaseReadTransaction * transaction ) {
if ( ! [ interaction isKindOfClass : TSIncomingMessage . class ] ) { return ; }
TSIncomingMessage * message = ( TSIncomingMessage * ) interaction ;
if ( message . friendRequestStatus ! = LKMessageFriendRequestStatusNone ) {
[ message saveFriendRequestStatus : LKMessageFriendRequestStatusNone withTransaction : transaction ] ;
2019-11-06 06:39:26 +01:00
}
} ] ;
2019-10-31 04:24:53 +01:00
}
2019-11-07 00:19:22 +01:00
message . friendRequestStatus = LKMessageFriendRequestStatusPending ; // Don ' t save yet . This is done in finalizeIncomingMessage : thread : masterThread : envelope : transaction .
2019-07-24 01:20:33 +02:00
}
}
2019-09-18 03:09:09 +02:00
- ( void ) handleFriendRequestAcceptanceIfNeededWithEnvelope : ( SSKProtoEnvelope * ) envelope transaction : ( YapDatabaseReadWriteTransaction * ) transaction {
// If we get an envelope that isn ' t a friend request , then we can infer that we had to use
// Signal cipher decryption and thus that we have a session with the other person .
2020-02-15 00:01:21 +01:00
// The envelope type is set during UD decryption .
2019-09-09 08:23:40 +02:00
if ( envelope . isGroupChatMessage || envelope . type = = SSKProtoEnvelopeTypeFriendRequest ) return ;
2019-10-31 06:52:22 +01:00
// Currently this uses ` envelope . source` but with sync messages we ' ll need to use the message sender ID
2019-07-24 01:20:33 +02:00
TSContactThread * thread = [ TSContactThread getOrCreateThreadWithContactId : envelope . source transaction : transaction ] ;
2020-01-29 04:58:28 +01:00
// We shouldn ' t be able to skip from none to friends under normal circumstances
2020-01-20 06:58:38 +01:00
if ( thread . friendRequestStatus = = LKThreadFriendRequestStatusNone ) { return ; }
2019-07-24 01:20:33 +02:00
// Become happy friends and go on great adventures
[ thread saveFriendRequestStatus : LKThreadFriendRequestStatusFriends withTransaction : transaction ] ;
2020-02-14 03:21:26 +01:00
TSOutgoingMessage * existingFriendRequestMessage = [ [ thread getLastInteractionWithTransaction : transaction ] as : TSOutgoingMessage . class ] ;
2020-02-04 07:19:44 +01:00
if ( existingFriendRequestMessage ! = nil && existingFriendRequestMessage . isFriendRequest ) {
[ existingFriendRequestMessage saveFriendRequestStatus : LKMessageFriendRequestStatusAccepted withTransaction : transaction ] ;
}
2019-07-24 01:20:33 +02:00
// Send our P2P details
LKAddressMessage * _Nullable onlineMessage = [ LKP2PAPI onlineBroadcastMessageForThread : thread ] ;
if ( onlineMessage ! = nil ) {
[ self . messageSenderJobQueue addMessage : onlineMessage transaction : transaction ] ;
2019-05-16 04:08:37 +02:00
}
2019-05-17 03:39:54 +02:00
}
- ( void ) finalizeIncomingMessage : ( TSIncomingMessage * ) incomingMessage
thread : ( TSThread * ) thread
2019-11-06 05:45:41 +01:00
masterThread : ( TSThread * ) masterThread
2019-05-17 03:39:54 +02:00
envelope : ( SSKProtoEnvelope * ) envelope
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return ;
}
if ( ! thread ) {
OWSFailDebug ( @ "Missing thread." ) ;
return ;
}
if ( ! incomingMessage ) {
OWSFailDebug ( @ "Missing incomingMessage." ) ;
return ;
}
if ( ! transaction ) {
OWSFail ( @ "Missing transaction." ) ;
return ;
}
2019-05-16 04:08:37 +02:00
2017-10-04 16:06:38 +02:00
[ incomingMessage saveWithTransaction : transaction ] ;
2019-05-20 05:01:04 +02:00
2019-10-31 06:52:22 +01:00
// Loki : Remove any old incoming messages
2019-05-20 05:01:04 +02:00
if ( incomingMessage . isFriendRequest ) {
2019-05-24 08:23:27 +02:00
[ thread removeOldIncomingFriendRequestMessagesIfNeededWithTransaction : transaction ] ;
2019-05-20 05:01:04 +02:00
}
2017-09-13 21:35:33 +02:00
2018-04-18 02:53:27 +02:00
// Any messages sent from the current user - from this device or another - should be automatically marked as read .
2019-11-06 05:45:41 +01:00
if ( [ ( masterThread . contactIdentifier ? : envelope . source ) isEqualToString : self . tsAccountManager . localNumber ] ) {
2017-10-04 16:06:38 +02:00
// Don ' t send a read receipt for messages sent by ourselves .
2018-04-18 02:53:27 +02:00
[ incomingMessage markAsReadAtTimestamp : envelope . timestamp sendReadReceipt : NO transaction : transaction ] ;
2017-10-04 16:06:38 +02:00
}
2016-09-08 20:21:10 +02:00
2019-01-22 17:45:00 +01:00
// Download the "non-message body" attachments .
NSMutableArray < NSString * > * otherAttachmentIds = [ incomingMessage . allAttachmentIds mutableCopy ] ;
if ( incomingMessage . attachmentIds ) {
[ otherAttachmentIds removeObjectsInArray : incomingMessage . attachmentIds ] ;
2019-01-17 17:56:21 +01:00
}
for ( NSString * attachmentId in otherAttachmentIds ) {
2019-01-28 16:28:26 +01:00
TSAttachment * _Nullable attachment =
[ TSAttachment fetchObjectWithUniqueID : attachmentId transaction : transaction ] ;
if ( ! [ attachment isKindOfClass : [ TSAttachmentPointer class ] ] ) {
OWSLogInfo ( @ "Skipping attachment stream." ) ;
2019-01-17 17:56:21 +01:00
continue ;
}
2019-01-28 16:28:26 +01:00
TSAttachmentPointer * _Nullable attachmentPointer = ( TSAttachmentPointer * ) attachment ;
2018-11-07 23:49:25 +01:00
2019-01-17 17:56:21 +01:00
OWSLogDebug ( @ "Downloading attachment for message: %lu" , ( unsigned long ) incomingMessage . timestamp ) ;
// Use a separate download for each attachment so that :
//
// * We update the message as each comes in .
// * Failures don ' t interfere with successes .
[ self . attachmentDownloads downloadAttachmentPointer : attachmentPointer
success : ^ ( NSArray < TSAttachmentStream * > * attachmentStreams ) {
[ self . dbConnection readWriteWithBlock : ^ ( YapDatabaseReadWriteTransaction * transaction ) {
TSAttachmentStream * _Nullable attachmentStream = attachmentStreams . firstObject ;
OWSAssertDebug ( attachmentStream ) ;
if ( attachmentStream && incomingMessage . quotedMessage . thumbnailAttachmentPointerId . length > 0 &&
[ attachmentStream . uniqueId
isEqualToString : incomingMessage . quotedMessage . thumbnailAttachmentPointerId ] ) {
[ incomingMessage setQuotedMessageThumbnailAttachmentStream : attachmentStream ] ;
[ incomingMessage saveWithTransaction : transaction ] ;
} else {
2019-01-22 16:17:11 +01:00
// We touch the message to trigger redraw of any views displaying it ,
// since the attachment might be a contact avatar , etc .
2018-08-30 16:31:01 +02:00
[ incomingMessage touchWithTransaction : transaction ] ;
2019-01-17 17:56:21 +01:00
}
2018-05-03 17:31:06 +02:00
} ] ;
2019-01-17 17:56:21 +01:00
}
failure : ^ ( NSError * error ) {
2020-02-15 00:01:21 +01:00
OWSLogWarn ( @ "Failed to download attachment for message: %lu with error: %@." ,
2019-01-17 17:56:21 +01:00
( unsigned long ) incomingMessage . timestamp ,
error ) ;
} ] ;
2018-05-03 17:31:06 +02:00
}
2019-01-17 17:56:21 +01:00
2017-10-04 16:06:38 +02:00
// In case we already have a read receipt for this new message ( this happens sometimes ) .
[ OWSReadReceiptManager . sharedManager applyEarlyReadReceiptsForIncomingMessage : incomingMessage
transaction : transaction ] ;
2016-10-05 17:42:44 +02:00
2017-10-04 16:06:38 +02:00
// Update thread preview in inbox
2019-11-06 05:45:41 +01:00
[ masterThread touchWithTransaction : transaction ] ;
2016-08-23 22:38:05 +02:00
2018-09-17 15:27:58 +02:00
[ SSKEnvironment . shared . notificationsManager notifyUserForIncomingMessage : incomingMessage
2019-11-06 05:45:41 +01:00
inThread : masterThread
2018-09-17 15:27:58 +02:00
transaction : transaction ] ;
2018-10-31 00:18:17 +01:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2019-11-06 05:45:41 +01:00
[ self . typingIndicators didReceiveIncomingMessageInThread : masterThread
recipientId : ( masterThread . contactIdentifier ? : envelope . source )
2018-10-31 00:18:17 +01:00
deviceId : envelope . sourceDevice ] ;
} ) ;
2015-12-07 03:31:43 +01:00
}
2016-10-14 23:00:29 +02:00
# pragma mark - helpers
2015-12-07 03:31:43 +01:00
2018-08-01 23:13:01 +02:00
- ( BOOL ) isDataMessageGroupAvatarUpdate : ( SSKProtoDataMessage * ) dataMessage
2016-10-14 23:00:29 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return NO ;
}
2018-08-08 19:41:12 +02:00
return ( dataMessage . group ! = nil && dataMessage . group . type = = SSKProtoGroupContextTypeUpdate
&& dataMessage . group . avatar ! = nil ) ;
2015-12-07 03:31:43 +01:00
}
2017-07-25 00:05:26 +02:00
/ * *
* @ returns
2017-10-03 19:41:48 +02:00
* Group or Contact thread for message , creating a new contact thread if necessary ,
* but never creating a new group thread .
2017-07-25 00:05:26 +02:00
* /
2018-08-01 16:45:21 +02:00
- ( nullable TSThread * ) threadForEnvelope : ( SSKProtoEnvelope * ) envelope
2018-08-01 23:13:01 +02:00
dataMessage : ( SSKProtoDataMessage * ) dataMessage
2017-10-03 19:41:48 +02:00
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
2016-10-05 17:42:44 +02:00
{
2018-08-30 16:31:01 +02:00
if ( ! envelope ) {
OWSFailDebug ( @ "Missing envelope." ) ;
return nil ;
}
if ( ! dataMessage ) {
OWSFailDebug ( @ "Missing dataMessage." ) ;
return nil ;
}
if ( ! transaction ) {
2018-09-11 00:56:22 +02:00
OWSFail ( @ "Missing transaction." ) ;
2018-08-30 16:31:01 +02:00
return nil ;
}
2017-09-13 21:35:33 +02:00
2018-08-08 19:41:12 +02:00
if ( dataMessage . group ) {
2017-10-03 19:41:48 +02:00
NSData * groupId = dataMessage . group . id ;
2018-09-06 19:01:24 +02:00
OWSAssertDebug ( groupId . length > 0 ) ;
2017-10-03 19:41:48 +02:00
TSGroupThread * _Nullable groupThread = [ TSGroupThread threadWithGroupId : groupId transaction : transaction ] ;
// This method should only be called from a code path that has already verified
// that this is a "known" group .
2018-09-06 19:01:24 +02:00
OWSAssertDebug ( groupThread ) ;
2017-10-03 19:41:48 +02:00
return groupThread ;
2016-10-05 17:42:44 +02:00
} else {
2017-09-13 21:35:33 +02:00
return [ TSContactThread getOrCreateThreadWithContactId : envelope . source transaction : transaction ] ;
2016-10-05 17:42:44 +02:00
}
}
2018-10-22 18:31:28 +02:00
# pragma mark -
- ( void ) checkForUnknownLinkedDevice : ( SSKProtoEnvelope * ) envelope
transaction : ( YapDatabaseReadWriteTransaction * ) transaction
{
OWSAssertDebug ( envelope ) ;
OWSAssertDebug ( transaction ) ;
NSString * localNumber = self . tsAccountManager . localNumber ;
if ( ! [ localNumber isEqualToString : envelope . source ] ) {
return ;
}
2018-10-30 21:15:27 +01:00
// Consult the device list cache we use for message sending
// whether or not we know about this linked device .
2018-10-22 18:31:28 +02:00
SignalRecipient * _Nullable recipient =
2018-10-31 20:39:38 +01:00
[ SignalRecipient registeredRecipientForRecipientId : localNumber mustHaveDevices : NO transaction : transaction ] ;
2018-10-22 18:31:28 +02:00
if ( ! recipient ) {
2019-11-15 03:56:35 +01:00
// OWSFailDebug ( @ "No local SignalRecipient." ) ;
2018-10-22 18:31:28 +02:00
} else {
BOOL isRecipientDevice = [ recipient . devices containsObject : @ ( envelope . sourceDevice ) ] ;
if ( ! isRecipientDevice ) {
OWSLogInfo ( @ "Message received from unknown linked device; adding to local SignalRecipient: %lu." ,
( unsigned long ) envelope . sourceDevice ) ;
[ recipient updateRegisteredRecipientWithDevicesToAdd : @ [ @ ( envelope . sourceDevice ) ]
devicesToRemove : nil
transaction : transaction ] ;
}
}
2018-10-30 21:15:27 +01:00
// Consult the device list cache we use for the "linked device" UI
// whether or not we know about this linked device .
2018-10-22 18:44:34 +02:00
NSMutableSet < NSNumber * > * deviceIdSet = [ NSMutableSet new ] ;
for ( OWSDevice * device in [ OWSDevice currentDevicesWithTransaction : transaction ] ) {
[ deviceIdSet addObject : @ ( device . deviceId ) ] ;
}
2018-10-22 18:31:28 +02:00
BOOL isInDeviceList = [ deviceIdSet containsObject : @ ( envelope . sourceDevice ) ] ;
if ( ! isInDeviceList ) {
OWSLogInfo ( @ "Message received from unknown linked device; refreshing device list: %lu." ,
( unsigned long ) envelope . sourceDevice ) ;
[ OWSDevicesService refreshDevices ] ;
2018-10-31 20:01:33 +01:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . profileManager fetchLocalUsersProfile ] ;
} ) ;
2018-10-22 18:31:28 +02:00
}
}
2015-12-07 03:31:43 +01:00
@ end
2016-10-05 17:42:44 +02:00
NS_ASSUME _NONNULL _END