From d1e02848e664a8cb723e036aae16a6e5f56e24f0 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 24 Jul 2019 09:20:33 +1000 Subject: [PATCH 1/3] Update friend request handling. --- .../src/Messages/OWSMessageManager.m | 96 +++++++++++-------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index f559d97a3..1fdac90f8 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -413,6 +413,9 @@ NS_ASSUME_NONNULL_BEGIN envelope.timestamp); return; } + + // Loki: Handle any friend request accepts if we need to + [self handleFriendRequestAcceptIfNeededWithEnvelope:envelope transaction:transaction]; if (envelope.content != nil) { NSError *error; @@ -1383,7 +1386,7 @@ NS_ASSUME_NONNULL_BEGIN } // Loki: Do this before the check below - [self handleFriendRequestIfNeededWithEnvelope:envelope message:incomingMessage thread:oldGroupThread transaction:transaction]; + [self handleFriendRequestMessageIfNeededWithEnvelope:envelope message:incomingMessage thread:oldGroupThread transaction:transaction]; if (body.length == 0 && attachmentPointers.count < 1 && !contact) { OWSLogWarn(@"ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu", @@ -1458,7 +1461,7 @@ NS_ASSUME_NONNULL_BEGIN } // Loki: Do this before the check below - [self handleFriendRequestIfNeededWithEnvelope:envelope message:incomingMessage thread:thread transaction:transaction]; + [self handleFriendRequestMessageIfNeededWithEnvelope:envelope message:incomingMessage thread:thread transaction:transaction]; if (body.length == 0 && attachmentPointers.count < 1 && !contact) { OWSLogWarn(@"ignoring empty incoming message from: %@ with timestamp: %lu", @@ -1486,50 +1489,61 @@ NS_ASSUME_NONNULL_BEGIN } } -- (void)handleFriendRequestIfNeededWithEnvelope:(SSKProtoEnvelope *)envelope message:(TSIncomingMessage *)message thread:(TSThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) { - 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. - [thread saveFriendRequestStatus:LKThreadFriendRequestStatusFriends withTransaction:transaction]; - TSOutgoingMessage *existingFriendRequestMessage = (TSOutgoingMessage *)[thread.lastInteraction as:TSOutgoingMessage.class]; - if (existingFriendRequestMessage != nil && existingFriendRequestMessage.isFriendRequest) { - [existingFriendRequestMessage saveFriendRequestStatus:LKMessageFriendRequestStatusAccepted withTransaction:transaction]; - } - // The two lines below are equivalent to calling [ThreadUtil enqueueAcceptFriendRequestMessageInThread:thread] - LKEphemeralMessage *emptyMessage = [[LKEphemeralMessage alloc] initInThread:thread]; - [self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction]; - } 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]; - message.friendRequestStatus = LKMessageFriendRequestStatusPending; // Don't save yet. This is done in finalizeIncomingMessage:thread:envelope:transaction. - } - } else if (!thread.isContactFriend) { - // If the thread's friend request status is not LKThreadFriendRequestStatusFriends, but we're receiving a message, - // it must be a friend request accepted message. Declining a friend request doesn't send a message. +// The difference between this function and `handleFriendRequestAcceptIfNeededWithEnvelope:` is that this will setup the incoming message for display to the user +// While `handleFriendRequestAcceptIfNeededWithEnvelope:` handles friend request accepting logic and doesn't need a message +- (void)handleFriendRequestMessageIfNeededWithEnvelope:(SSKProtoEnvelope *)envelope message:(TSIncomingMessage *)message thread:(TSThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction { + // Check if it's a friend request message + if (envelope.type != SSKProtoEnvelopeTypeFriendRequest) return; + + 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. [thread saveFriendRequestStatus:LKThreadFriendRequestStatusFriends withTransaction:transaction]; TSOutgoingMessage *existingFriendRequestMessage = (TSOutgoingMessage *)[thread.lastInteraction as:TSOutgoingMessage.class]; if (existingFriendRequestMessage != nil && existingFriendRequestMessage.isFriendRequest) { [existingFriendRequestMessage saveFriendRequestStatus:LKMessageFriendRequestStatusAccepted withTransaction:transaction]; } - // Send our P2P details - LKAddressMessage *_Nullable onlineMessage = [LKP2PAPI onlineBroadcastMessageForThread:thread]; - if (onlineMessage != nil) { - [self.messageSenderJobQueue addMessage:onlineMessage transaction:transaction]; - } + // The two lines below are equivalent to calling [ThreadUtil enqueueAcceptFriendRequestMessageInThread:thread] + LKEphemeralMessage *emptyMessage = [[LKEphemeralMessage alloc] initInThread:thread]; + [self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction]; + } 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]; + message.friendRequestStatus = LKMessageFriendRequestStatusPending; // Don't save yet. This is done in finalizeIncomingMessage:thread:envelope:transaction. + } +} + +- (void)handleFriendRequestAcceptIfNeededWithEnvelope:(SSKProtoEnvelope *)envelope transaction:(YapDatabaseReadWriteTransaction *)transaction { + // If we get any other envelope type then we can assume that we had to use signal cipher decryption + // and that means we must have a session with the other person. + if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) return; + + // If we're already friends then there's no point in continuing + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; + if (thread.isContactFriend) return; + + // Become happy friends and go on great adventures + [thread saveFriendRequestStatus:LKThreadFriendRequestStatusFriends withTransaction:transaction]; + TSOutgoingMessage *existingFriendRequestMessage = (TSOutgoingMessage *)[thread.lastInteraction as:TSOutgoingMessage.class]; + if (existingFriendRequestMessage != nil && existingFriendRequestMessage.isFriendRequest) { + [existingFriendRequestMessage saveFriendRequestStatus:LKMessageFriendRequestStatusAccepted withTransaction:transaction]; + } + // Send our P2P details + LKAddressMessage *_Nullable onlineMessage = [LKP2PAPI onlineBroadcastMessageForThread:thread]; + if (onlineMessage != nil) { + [self.messageSenderJobQueue addMessage:onlineMessage transaction:transaction]; } } From 9ec9b0e27ffcf1319fc3785f227d8bf8bdcbc530 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 24 Jul 2019 09:35:35 +1000 Subject: [PATCH 2/3] Don't set content data in LKEphemeralMessage. --- .../src/Loki/Messaging/LKEphemeralMessage.m | 15 +++++++++++++++ SignalServiceKit/src/Messages/OWSMessageManager.m | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Loki/Messaging/LKEphemeralMessage.m b/SignalServiceKit/src/Loki/Messaging/LKEphemeralMessage.m index 8aefa3f7d..3996509aa 100644 --- a/SignalServiceKit/src/Loki/Messaging/LKEphemeralMessage.m +++ b/SignalServiceKit/src/Loki/Messaging/LKEphemeralMessage.m @@ -1,5 +1,6 @@ #import "LKEphemeralMessage.h" #import +#import @implementation LKEphemeralMessage @@ -8,6 +9,20 @@ expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil]; } +// An EphemeralMessage does not have any data message in the content +- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient +{ + NSError *error; + SSKProtoContentBuilder *contentBuilder = [self contentBuilder:recipient]; + + NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; + if (error || !contentData) { + OWSFailDebug(@"could not serialize protobuf: %@", error); + return nil; + } + return contentData; +} + - (BOOL)shouldSyncTranscript { return NO; } - (BOOL)shouldBeSaved { return NO; } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 1fdac90f8..9e9152919 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1512,8 +1512,8 @@ NS_ASSUME_NONNULL_BEGIN [existingFriendRequestMessage saveFriendRequestStatus:LKMessageFriendRequestStatusAccepted withTransaction:transaction]; } // The two lines below are equivalent to calling [ThreadUtil enqueueAcceptFriendRequestMessageInThread:thread] - LKEphemeralMessage *emptyMessage = [[LKEphemeralMessage alloc] initInThread:thread]; - [self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction]; + LKEphemeralMessage *backgroundMessage = [[LKEphemeralMessage alloc] initInThread:thread]; + [self.messageSenderJobQueue addMessage:backgroundMessage transaction:transaction]; } 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 From 162c9db6fe50356ffbc01c21b0a971e8270357e1 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 24 Jul 2019 12:21:30 +1000 Subject: [PATCH 3/3] Added TODO reminder. --- SignalServiceKit/src/Messages/OWSMessageManager.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 9e9152919..b170700f4 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1531,6 +1531,8 @@ NS_ASSUME_NONNULL_BEGIN if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) return; // If we're already friends then there's no point in continuing + // TODO: We'll need to fix this up if we ever start using Sync messages + // Currently it'll use `envelope.source` but with sync messages we need to use the message sender id TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; if (thread.isContactFriend) return;