From 3dc7494b167486403a19e47eb8ea2ae6f23cba70 Mon Sep 17 00:00:00 2001
From: Ryan ZHAO <ryanzhaors@qq.com>
Date: Fri, 17 Jan 2020 10:38:16 +1100
Subject: [PATCH] Handle session request message for group members

---
 .../Loki/Messaging/LKSessionRequestMessage.h  | 15 ++++++++++++
 .../Loki/Messaging/LKSessionRequestMessage.m  | 20 ++++++++++++++++
 .../src/Messages/OWSMessageManager.m          | 23 +++++++++++++++++++
 .../src/Messages/OWSMessageSender.m           | 12 ++++++----
 4 files changed, 66 insertions(+), 4 deletions(-)
 create mode 100644 SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.h
 create mode 100644 SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.m

diff --git a/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.h b/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.h
new file mode 100644
index 000000000..5a8996a4b
--- /dev/null
+++ b/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.h
@@ -0,0 +1,15 @@
+//
+//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
+// 
+
+#import "LKFriendRequestMessage.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface LKSessionRequestMessage : LKFriendRequestMessage
+
+- (instancetype)initWithThread:(TSThread *)thread;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.m b/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.m
new file mode 100644
index 000000000..56d699199
--- /dev/null
+++ b/SignalServiceKit/src/Loki/Messaging/LKSessionRequestMessage.m
@@ -0,0 +1,20 @@
+//
+//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
+// 
+
+#import "LKSessionRequestMessage.h"
+#import <SignalCoreKit/NSDate+OWS.h>
+#import <SignalServiceKit/SignalServiceKit-Swift.h>
+
+@implementation LKSessionRequestMessage
+
+- (instancetype)initWithThread:(TSThread *)thread {
+    return [self initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"" attachmentIds:[NSMutableArray<NSString *> new]
+        expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil];
+}
+
+- (BOOL)shouldBeSaved {
+    return NO;
+}
+
+@end
diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m
index 17e094e2d..538d36178 100644
--- a/SignalServiceKit/src/Messages/OWSMessageManager.m
+++ b/SignalServiceKit/src/Messages/OWSMessageManager.m
@@ -20,6 +20,7 @@
 #import "OWSDisappearingMessagesConfiguration.h"
 #import "OWSDisappearingMessagesJob.h"
 #import "LKEphemeralMessage.h"
+#import "LKSessionRequestMessage.h"
 #import "LKDeviceLinkMessage.h"
 #import "OWSIdentityManager.h"
 #import "OWSIncomingMessageFinder.h"
@@ -577,6 +578,7 @@ NS_ASSUME_NONNULL_BEGIN
             // Unknown group.
             if (dataMessage.group.type == SSKProtoGroupContextTypeUpdate) {
                 // Accept group updates for unknown groups.
+                OWSLogInfo(@"RYAN: Group update message for unknown groups, %@", dataMessage.body);
             } else if (dataMessage.group.type == SSKProtoGroupContextTypeDeliver) {
                 [self sendGroupInfoRequest:dataMessage.group.id envelope:envelope transaction:transaction];
                 return;
@@ -1405,6 +1407,9 @@ NS_ASSUME_NONNULL_BEGIN
                                                                                   contactsManager:self.contactsManager];
                 newGroupThread.groupModel = newGroupModel;
                 [newGroupThread saveWithTransaction:transaction];
+                
+                //Loki - Try to establish session with members when a group is created or updated
+                [self establishSessionsWithMembersIfNeeded: newMemberIds.allObjects forThread:newGroupThread transaction:transaction];
 
                 [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
                                                                                           thread:newGroupThread
@@ -1648,6 +1653,24 @@ NS_ASSUME_NONNULL_BEGIN
     }
 }
 
+//Loki: Establish a session if there is no session between the memebers of a group
+- (void)establishSessionsWithMembersIfNeeded: (NSArray *)members forThread: (TSGroupThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction
+{
+    NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
+    for (NSString *member in members) {
+        if ([member isEqualToString:userHexEncodedPublicKey] ) { continue; }
+        TSThread *contactThread = [TSContactThread getThreadWithContactId:member transaction:transaction];
+        if (contactThread == nil || !contactThread.isContactFriend) {
+            OWSLogInfo(@"Try to build session with %@", member);
+          LKSessionRequestMessage *message = [[LKSessionRequestMessage alloc] initWithThread:thread];
+          [self.messageSenderJobQueue addMessage:message transaction:transaction];
+        }
+        else {
+            OWSLogInfo(@"There is session with %@", member);
+        }
+    }
+}
+
 - (BOOL)canFriendRequestBeAutoAcceptedForThread:(TSContactThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction
 {
     NSString *senderHexEncodedPublicKey = thread.contactIdentifier;
diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m
index 8dc2db28a..901d3c11b 100644
--- a/SignalServiceKit/src/Messages/OWSMessageSender.m
+++ b/SignalServiceKit/src/Messages/OWSMessageSender.m
@@ -45,6 +45,7 @@
 #import "TSThread.h"
 #import "TSContactThread.h"
 #import "LKFriendRequestMessage.h"
+#import "LKSessionRequestMessage.h"
 #import "LKDeviceLinkMessage.h"
 #import "LKAddressMessage.h"
 #import <AxolotlKit/AxolotlExceptions.h>
@@ -960,6 +961,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
     } else {
         BOOL isSilentMessage = message.isSilent || [message isKindOfClass:LKEphemeralMessage.class] || [message isKindOfClass:OWSOutgoingSyncMessage.class];
         BOOL isFriendRequestMessage = [message isKindOfClass:LKFriendRequestMessage.class];
+        BOOL isSessionRequestMessage = [message isKindOfClass:LKSessionRequestMessage.class];
         [[LKAPI getDestinationsFor:contactID]
         .thenOn(OWSDispatch.sendingQueue, ^(NSArray<LKDestination *> *destinations) {
             // Get master destination
@@ -969,7 +971,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
             // Send to master destination
             if (masterDestination != nil) {
                 TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:masterDestination.hexEncodedPublicKey];
-                if (thread.isContactFriend || isSilentMessage || isFriendRequestMessage) {
+                if (thread.isContactFriend || isSilentMessage || isFriendRequestMessage || isSessionRequestMessage) {
                     OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:masterDestination];
                     [self sendMessage:messageSendCopy];
                 } else {
@@ -984,7 +986,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
             // Send to slave destinations (using a best attempt approach (i.e. ignoring the message send result) for now)
             for (LKDestination *slaveDestination in slaveDestinations) {
                 TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:slaveDestination.hexEncodedPublicKey];
-                if (thread.isContactFriend || isSilentMessage || isFriendRequestMessage) {
+                if (thread.isContactFriend || isSilentMessage || isFriendRequestMessage || isSessionRequestMessage) {
                     OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:slaveDestination];
                     [self sendMessage:messageSendCopy];
                 } else {
@@ -1698,8 +1700,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
             
             // Loki: Both for friend request messages and device link messages we don't require a session
             BOOL isFriendRequest = [messageSend.message isKindOfClass:LKFriendRequestMessage.class];
+            BOOL isSessionRequest = [messageSend.message isKindOfClass:LKSessionRequestMessage.class];
             BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class];
-            if (!isFriendRequest && !(isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
+            if (!isFriendRequest && !isSessionRequest && !(isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
                 [self throws_ensureRecipientHasSessionForMessageSend:messageSend recipientID:recipientID deviceId:@(OWSDevicePrimaryDeviceId)];
             }
 
@@ -1943,8 +1946,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
     
     // Loki: Both for friend request messages and device link messages we use fallback encryption as we don't necessarily have a session yet
     BOOL isFriendRequest = [messageSend.message isKindOfClass:LKFriendRequestMessage.class];
+    BOOL isSessionRequest = [messageSend.message isKindOfClass:LKSessionRequestMessage.class];
     BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class];
-    if (isFriendRequest || (isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
+    if (isFriendRequest || isSessionRequest || (isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
         return [self throws_encryptedFriendRequestOrDeviceLinkMessageForMessageSend:messageSend deviceId:@(OWSDevicePrimaryDeviceId) plainText:plainText];
     }