From 1a156c604ac1b39eaded5f5574621c311a7d22d0 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 12 Feb 2020 16:31:37 +1100 Subject: [PATCH 01/19] enable to send the group sync message --- .../View Controllers/DeviceLinkingModal.swift | 1 + SignalMessaging/contacts/OWSSyncManager.m | 19 ++++++++ SignalServiceKit/protobuf/SignalService.proto | 4 +- .../src/Devices/OWSGroupsOutputStream.m | 1 + .../DeviceSyncing/OWSSyncGroupsMessage.m | 43 ++++++++++++------- .../src/Messages/OWSMessageManager.m | 8 +++- .../src/Protos/Generated/SSKProto.swift | 31 +++++++++++++ .../Protos/Generated/SignalService.pb.swift | 32 ++++++++++++++ .../src/TestUtils/OWSMockSyncManager.swift | 6 +++ .../src/Util/OWSSyncManagerProtocol.h | 2 + 10 files changed, 129 insertions(+), 18 deletions(-) diff --git a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift index 9ce16ef95..ba52bcf11 100644 --- a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift +++ b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift @@ -166,6 +166,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { ThreadUtil.enqueue(linkingAuthorizationMessage) SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: { let _ = SSKEnvironment.shared.syncManager.syncAllContacts() + _ = SSKEnvironment.shared.syncManager.syncAllGroups() }) { _ in print("[Loki] Failed to send device link authorization message.") } diff --git a/SignalMessaging/contacts/OWSSyncManager.m b/SignalMessaging/contacts/OWSSyncManager.m index a7532e918..8acbe1d45 100644 --- a/SignalMessaging/contacts/OWSSyncManager.m +++ b/SignalMessaging/contacts/OWSSyncManager.m @@ -16,6 +16,7 @@ #import #import #import +#import #import #import #import @@ -303,6 +304,24 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag return promise; } +- (AnyPromise *)syncAllGroups +{ + OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init]; + AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { + [self.messageSender sendMessage:syncGroupsMessage + success:^{ + OWSLogInfo(@"Successfully sent groups sync message."); + resolve(@(1)); + } + failure:^(NSError *error) { + OWSLogError(@"Failed to send groups sync message with error: %@.", error); + resolve(error); + }]; + }]; + [promise retainUntilComplete]; + return promise; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index aad7efdb2..0c9ee9425 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -319,6 +319,7 @@ message SyncMessage { message Groups { optional AttachmentPointer blob = 1; + optional bytes data = 101; // Loki } message Blocked { @@ -399,7 +400,7 @@ message GroupContext { optional string name = 3; repeated string members = 4; optional AttachmentPointer avatar = 5; - repeated string admins = 6; + repeated string admins = 6; // Loki } message ContactDetails { @@ -435,6 +436,7 @@ message GroupDetails { optional uint32 expireTimer = 6; optional string color = 7; optional bool blocked = 8; + repeated string admins = 9; // Loki } // Internal - DO NOT SEND diff --git a/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m b/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m index 80ba744a7..ba323f7ae 100644 --- a/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m +++ b/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m @@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN [groupBuilder setName:group.groupName]; [groupBuilder setMembers:group.groupMemberIds]; [groupBuilder setColor:groupThread.conversationColorName]; + [groupBuilder setAdmins:group.groupAdminIds]; if ([OWSBlockingManager.sharedManager isGroupIdBlocked:group.groupId]) { [groupBuilder setBlocked:YES]; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m index f76b36f87..5bce40231 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m @@ -11,6 +11,7 @@ #import "TSGroupThread.h" #import #import +#import "OWSPrimaryStorage.h" NS_ASSUME_NONNULL_BEGIN @@ -28,22 +29,32 @@ NS_ASSUME_NONNULL_BEGIN - (nullable SSKProtoSyncMessageBuilder *)syncMessageBuilder { - if (self.attachmentIds.count != 1) { - OWSLogError(@"expected sync groups message to have exactly one attachment, but found %lu", - (unsigned long)self.attachmentIds.count); - } - - SSKProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; - if (!attachmentProto) { - OWSFailDebug(@"could not build protobuf."); - return nil; - } - - SSKProtoSyncMessageGroupsBuilder *groupsBuilder = [SSKProtoSyncMessageGroups builder]; - [groupsBuilder setBlob:attachmentProto]; - NSError *error; + if (self.attachmentIds.count > 1) { + OWSLogError(@"Expected sync group message to have one or zero attachments, but found %lu.", (unsigned long)self.attachmentIds.count); + } + + SSKProtoSyncMessageGroupsBuilder *groupsBuilder; + if (self.attachmentIds.count == 0) { + SSKProtoAttachmentPointerBuilder *attachmentProtoBuilder = [SSKProtoAttachmentPointer builderWithId:0]; + SSKProtoAttachmentPointer *attachmentProto = [attachmentProtoBuilder buildAndReturnError:&error]; + groupsBuilder = [SSKProtoSyncMessageGroups builder]; + [groupsBuilder setBlob:attachmentProto]; + __block NSData *data; + [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + data = [self buildPlainTextAttachmentDataWithTransaction:transaction]; + }]; + [groupsBuilder setData:data]; + } else { + SSKProtoAttachmentPointer *attachmentProto = [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; + if (attachmentProto == nil) { + OWSFailDebug(@"Couldn't build protobuf."); + return nil; + } + groupsBuilder = [SSKProtoSyncMessageGroups builder]; + [groupsBuilder setBlob:attachmentProto]; + } + SSKProtoSyncMessageGroups *_Nullable groupsProto = [groupsBuilder buildAndReturnError:&error]; if (error || !groupsProto) { OWSFailDebug(@"could not build protobuf: %@", error); @@ -68,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN [TSGroupThread enumerateCollectionObjectsWithTransaction:transaction usingBlock:^(id obj, BOOL *stop) { - if (![obj isKindOfClass:[TSGroupThread class]]) { + if (![obj isKindOfClass:[TSGroupThread class]] || ((TSGroupThread *)obj).groupModel.groupType != closedGroup) { if (![obj isKindOfClass:[TSContactThread class]]) { OWSLogWarn( @"Ignoring non group thread in thread collection: %@", obj); diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 4af814e77..a1646c07c 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1074,7 +1074,7 @@ NS_ASSUME_NONNULL_BEGIN [self.identityManager throws_processIncomingSyncMessage:syncMessage.verified transaction:transaction]; } else if (syncMessage.contacts != nil) { if (wasSentByMasterDevice && syncMessage.contacts.data.length > 0) { - NSLog(@"[Loki] Received contact sync message."); + OWSLogInfo(@"[Loki] Received contact sync message."); NSData *data = syncMessage.contacts.data; ContactParser *parser = [[ContactParser alloc] initWithData:data]; NSArray *hexEncodedPublicKeys = [parser parseHexEncodedPublicKeys]; @@ -1102,6 +1102,12 @@ NS_ASSUME_NONNULL_BEGIN } } } + } else if (syncMessage.groups != nil) { + if (wasSentByMasterDevice && syncMessage.groups.data.length > 0) { + OWSLogInfo(@"[Loki] Received group sync message."); + NSData *data = syncMessage.groups.data; + // TODO: decode the data and handle the group info + } } else { OWSLogWarn(@"Ignoring unsupported sync message."); } diff --git a/SignalServiceKit/src/Protos/Generated/SSKProto.swift b/SignalServiceKit/src/Protos/Generated/SSKProto.swift index c94ca5861..1884be9fd 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProto.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProto.swift @@ -4551,6 +4551,9 @@ extension SSKProtoSyncMessageContacts.SSKProtoSyncMessageContactsBuilder { if let _value = blob { builder.setBlob(_value) } + if let _value = data { + builder.setData(_value) + } return builder } @@ -4563,6 +4566,10 @@ extension SSKProtoSyncMessageContacts.SSKProtoSyncMessageContactsBuilder { @objc public func setBlob(_ valueParam: SSKProtoAttachmentPointer) { proto.blob = valueParam.proto } + + @objc public func setData(_ valueParam: Data) { + proto.data = valueParam + } @objc public func build() throws -> SSKProtoSyncMessageGroups { return try SSKProtoSyncMessageGroups.parseProto(proto) @@ -4576,6 +4583,16 @@ extension SSKProtoSyncMessageContacts.SSKProtoSyncMessageContactsBuilder { fileprivate let proto: SignalServiceProtos_SyncMessage.Groups @objc public let blob: SSKProtoAttachmentPointer? + + @objc public var data: Data? { + guard proto.hasData else { + return nil + } + return proto.data + } + @objc public var hasData: Bool { + return proto.hasData + } private init(proto: SignalServiceProtos_SyncMessage.Groups, blob: SSKProtoAttachmentPointer?) { @@ -6343,6 +6360,16 @@ extension SSKProtoGroupDetailsAvatar.SSKProtoGroupDetailsAvatarBuilder { @objc public func setMembers(_ wrappedItems: [String]) { proto.members = wrappedItems } + + @objc public func addAdmins(_ valueParam: String) { + var items = proto.admins + items.append(valueParam) + proto.admins = items + } + + @objc public func setAdmins(_ wrappedItems: [String]) { + proto.admins = wrappedItems + } @objc public func setAvatar(_ valueParam: SSKProtoGroupDetailsAvatar) { proto.avatar = valueParam.proto @@ -6392,6 +6419,10 @@ extension SSKProtoGroupDetailsAvatar.SSKProtoGroupDetailsAvatarBuilder { @objc public var members: [String] { return proto.members } + + @objc public var admins: [String] { + return proto.admins + } @objc public var active: Bool { return proto.active diff --git a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift index 2b433616e..f81521781 100644 --- a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift +++ b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift @@ -1945,6 +1945,16 @@ struct SignalServiceProtos_SyncMessage { var hasBlob: Bool {return _storage._blob != nil} /// Clears the value of `blob`. Subsequent reads from it will return its default value. mutating func clearBlob() {_uniqueStorage()._blob = nil} + + /// Loki + var data: Data { + get {return _storage._data ?? SwiftProtobuf.Internal.emptyData} + set {_uniqueStorage()._data = newValue} + } + /// Returns true if `data` has been explicitly set. + var hasData: Bool {return _storage._data != nil} + /// Clears the value of `data`. Subsequent reads from it will return its default value. + mutating func clearData() {_uniqueStorage()._data = nil} var unknownFields = SwiftProtobuf.UnknownStorage() @@ -2534,6 +2544,12 @@ struct SignalServiceProtos_GroupDetails { get {return _storage._members} set {_uniqueStorage()._members = newValue} } + + ///Loki + var admins: [String] { + get {return _storage._admins} + set {_uniqueStorage()._admins = newValue} + } var avatar: SignalServiceProtos_GroupDetails.Avatar { get {return _storage._avatar ?? SignalServiceProtos_GroupDetails.Avatar()} @@ -4627,10 +4643,12 @@ extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftPr static let protoMessageName: String = SignalServiceProtos_SyncMessage.protoMessageName + ".Groups" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "blob"), + 101: .same(proto: "data"), ] fileprivate class _StorageClass { var _blob: SignalServiceProtos_AttachmentPointer? = nil + var _data: Data? = nil static let defaultInstance = _StorageClass() @@ -4638,6 +4656,7 @@ extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftPr init(copying source: _StorageClass) { _blob = source._blob + _data = source._data } } @@ -4654,6 +4673,7 @@ extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftPr while let fieldNumber = try decoder.nextFieldNumber() { switch fieldNumber { case 1: try decoder.decodeSingularMessageField(value: &_storage._blob) + case 101: try decoder.decodeSingularBytesField(value: &_storage._data) default: break } } @@ -4665,6 +4685,9 @@ extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftPr if let v = _storage._blob { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) } + if let v = _storage._data { + try visitor.visitSingularBytesField(value: v, fieldNumber: 101) + } } try unknownFields.traverse(visitor: &visitor) } @@ -4675,6 +4698,7 @@ extension SignalServiceProtos_SyncMessage.Groups: SwiftProtobuf.Message, SwiftPr let _storage = _args.0 let rhs_storage = _args.1 if _storage._blob != rhs_storage._blob {return false} + if _storage._data != rhs_storage._data {return false} return true } if !storagesAreEqual {return false} @@ -5223,6 +5247,7 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf 6: .same(proto: "expireTimer"), 7: .same(proto: "color"), 8: .same(proto: "blocked"), + 9: .same(proto: "admins"), ] fileprivate class _StorageClass { @@ -5234,6 +5259,7 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf var _expireTimer: UInt32? = nil var _color: String? = nil var _blocked: Bool? = nil + var _admins: [String] = [] static let defaultInstance = _StorageClass() @@ -5248,6 +5274,7 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf _expireTimer = source._expireTimer _color = source._color _blocked = source._blocked + _admins = source._admins } } @@ -5271,6 +5298,7 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf case 6: try decoder.decodeSingularUInt32Field(value: &_storage._expireTimer) case 7: try decoder.decodeSingularStringField(value: &_storage._color) case 8: try decoder.decodeSingularBoolField(value: &_storage._blocked) + case 9: try decoder.decodeRepeatedStringField(value: &_storage._admins) default: break } } @@ -5303,6 +5331,9 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf if let v = _storage._blocked { try visitor.visitSingularBoolField(value: v, fieldNumber: 8) } + if !_storage._admins.isEmpty { + try visitor.visitRepeatedStringField(value: _storage._admins, fieldNumber: 9) + } } try unknownFields.traverse(visitor: &visitor) } @@ -5320,6 +5351,7 @@ extension SignalServiceProtos_GroupDetails: SwiftProtobuf.Message, SwiftProtobuf if _storage._expireTimer != rhs_storage._expireTimer {return false} if _storage._color != rhs_storage._color {return false} if _storage._blocked != rhs_storage._blocked {return false} + if _storage._admins != rhs_storage._admins {return false} return true } if !storagesAreEqual {return false} diff --git a/SignalServiceKit/src/TestUtils/OWSMockSyncManager.swift b/SignalServiceKit/src/TestUtils/OWSMockSyncManager.swift index a3dcb9187..e408b8aaf 100644 --- a/SignalServiceKit/src/TestUtils/OWSMockSyncManager.swift +++ b/SignalServiceKit/src/TestUtils/OWSMockSyncManager.swift @@ -9,6 +9,12 @@ import PromiseKit @objc public class OWSMockSyncManager: NSObject, OWSSyncManagerProtocol { + public func syncAllGroups() -> AnyPromise { + Logger.info("") + + return AnyPromise() + } + @objc public func sendConfigurationSyncMessage() { Logger.info("") diff --git a/SignalServiceKit/src/Util/OWSSyncManagerProtocol.h b/SignalServiceKit/src/Util/OWSSyncManagerProtocol.h index eafb2e6fa..e0b78c36b 100644 --- a/SignalServiceKit/src/Util/OWSSyncManagerProtocol.h +++ b/SignalServiceKit/src/Util/OWSSyncManagerProtocol.h @@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN - (AnyPromise *)syncContactsForSignalAccounts:(NSArray *)signalAccounts __attribute__((warn_unused_result)); +- (AnyPromise *)syncAllGroups __attribute__((warn_unused_result)); + @end NS_ASSUME_NONNULL_END From b5ce94c6ab361bed5014b92b26d2f6c7c3ae3d05 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 12 Feb 2020 17:08:27 +1100 Subject: [PATCH 02/19] add group parser --- .../src/Loki/Messaging/GroupParser.swift | 34 +++++++++++++++++++ .../src/Messages/OWSMessageManager.m | 1 + 2 files changed, 35 insertions(+) create mode 100644 SignalServiceKit/src/Loki/Messaging/GroupParser.swift diff --git a/SignalServiceKit/src/Loki/Messaging/GroupParser.swift b/SignalServiceKit/src/Loki/Messaging/GroupParser.swift new file mode 100644 index 000000000..6afa2386a --- /dev/null +++ b/SignalServiceKit/src/Loki/Messaging/GroupParser.swift @@ -0,0 +1,34 @@ + +@objc public final class GroupParser : NSObject { + private let data: Data + + @objc public init(data: Data) { + self.data = data + } + + @objc public func parseGroupModels() -> [TSGroupModel] { + var index = 0 + var result: [TSGroupModel] = [] + while index < data.endIndex { + var uncheckedSize: UInt32? = try? data[index..<(index+4)].withUnsafeBytes { $0.pointee } + if let size = uncheckedSize, size >= data.count, let intermediate = try? data[index..<(index+4)].reversed() { + uncheckedSize = Data(intermediate).withUnsafeBytes { $0.pointee } + } + guard let size = uncheckedSize, size < data.count else { break } + let sizeAsInt = Int(size) + index += 4 + guard index + sizeAsInt < data.count else { break } + let protoAsData = data[index..<(index+sizeAsInt)] + guard let proto = try? SSKProtoGroupDetails.parseData(protoAsData) else { break } + index += sizeAsInt + var groupModel = TSGroupModel.init(title: proto.name, + memberIds: proto.members, + image: nil, + groupId: proto.id, + groupType: GroupType.closedGroup, + adminIds: proto.admins) + result.append(groupModel) + } + return result + } +} diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index a1646c07c..c864473ee 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1107,6 +1107,7 @@ NS_ASSUME_NONNULL_BEGIN OWSLogInfo(@"[Loki] Received group sync message."); NSData *data = syncMessage.groups.data; // TODO: decode the data and handle the group info + GroupParser *parser = [[GroupParser alloc] initWithData:data]; } } else { OWSLogWarn(@"Ignoring unsupported sync message."); From 9e1681558eec2651563815a5905d476a83747a01 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 12 Feb 2020 17:14:52 +1100 Subject: [PATCH 03/19] handle sync message of closed groups --- SignalServiceKit/src/Messages/OWSMessageManager.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index c864473ee..e5b0d14e4 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1108,6 +1108,11 @@ NS_ASSUME_NONNULL_BEGIN NSData *data = syncMessage.groups.data; // TODO: decode the data and handle the group info GroupParser *parser = [[GroupParser alloc] initWithData:data]; + NSArray *groupModels = [parser parseGroupModels]; + for (TSGroupModel *groupModel in groupModels) { + TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel]; + [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; + } } } else { OWSLogWarn(@"Ignoring unsupported sync message."); From cfe435bcd1c65294d5806257ce0e802aef426d12 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Thu, 13 Feb 2020 13:54:20 +1100 Subject: [PATCH 04/19] fix group parser --- SignalServiceKit/src/Devices/OWSGroupsOutputStream.m | 12 ++++++------ .../src/Loki/Messaging/GroupParser.swift | 2 +- SignalServiceKit/src/Messages/OWSMessageManager.m | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m b/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m index ba323f7ae..fe14f15c3 100644 --- a/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m +++ b/SignalServiceKit/src/Devices/OWSGroupsOutputStream.m @@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN if ([OWSBlockingManager.sharedManager isGroupIdBlocked:group.groupId]) { [groupBuilder setBlocked:YES]; } - + /* NSData *avatarPng; if (group.groupImage) { SSKProtoGroupDetailsAvatarBuilder *avatarBuilder = [SSKProtoGroupDetailsAvatar builder]; @@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN } else { [groupBuilder setAvatar:avatarProto]; } - } + } */ OWSDisappearingMessagesConfiguration *_Nullable disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:groupThread.uniqueId transaction:transaction]; @@ -70,12 +70,12 @@ NS_ASSUME_NONNULL_BEGIN uint32_t groupDataLength = (uint32_t)groupData.length; - [self writeVariableLengthUInt32:groupDataLength]; + [self writeUInt32:groupDataLength]; [self writeData:groupData]; - if (avatarPng) { - [self writeData:avatarPng]; - } +// if (avatarPng) { +// [self writeData:avatarPng]; +// } } @end diff --git a/SignalServiceKit/src/Loki/Messaging/GroupParser.swift b/SignalServiceKit/src/Loki/Messaging/GroupParser.swift index 6afa2386a..3c3fd68b1 100644 --- a/SignalServiceKit/src/Loki/Messaging/GroupParser.swift +++ b/SignalServiceKit/src/Loki/Messaging/GroupParser.swift @@ -17,7 +17,7 @@ guard let size = uncheckedSize, size < data.count else { break } let sizeAsInt = Int(size) index += 4 - guard index + sizeAsInt < data.count else { break } + guard index + sizeAsInt <= data.count else { break } let protoAsData = data[index..<(index+sizeAsInt)] guard let proto = try? SSKProtoGroupDetails.parseData(protoAsData) else { break } index += sizeAsInt diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index e5b0d14e4..109561c1c 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1110,7 +1110,7 @@ NS_ASSUME_NONNULL_BEGIN GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { - TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel]; + TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; } } From d5d88c55895b6a44f02a6a10a43cbaa85c52f348 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 14 Feb 2020 09:30:34 +1100 Subject: [PATCH 05/19] fix the bug when sending the friend request for a contact sync message --- .../src/Messages/OWSMessageManager.m | 12 +++++++----- SignalServiceKit/src/Messages/OWSMessageSender.h | 3 +++ SignalServiceKit/src/Messages/OWSMessageSender.m | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 109561c1c..1f136d051 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1085,10 +1085,12 @@ NS_ASSUME_NONNULL_BEGIN switch (friendRequestStatus) { case LKThreadFriendRequestStatusNone: { OWSMessageSender *messageSender = SSKEnvironment.shared.messageSender; - OWSMessageSend *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey]; - dispatch_async(OWSDispatch.sendingQueue, ^{ - [messageSender sendMessage:automatedFriendRequestMessage]; - }); +// OWSMessageSend *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey]; +// dispatch_async(OWSDispatch.sendingQueue, ^{ +// [messageSender sendMessage:automatedFriendRequestMessage]; +// }); + LKFriendRequestMessage *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey inThread:thread transaction:transaction]; + [self.messageSenderJobQueue addMessage:automatedFriendRequestMessage transaction:transaction]; break; } case LKThreadFriendRequestStatusRequestReceived: { @@ -1106,11 +1108,11 @@ NS_ASSUME_NONNULL_BEGIN if (wasSentByMasterDevice && syncMessage.groups.data.length > 0) { OWSLogInfo(@"[Loki] Received group sync message."); NSData *data = syncMessage.groups.data; - // TODO: decode the data and handle the group info GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; + //TODO: Join the group and send update group information [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; } } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index f223aadcf..b6af35dc2 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -3,6 +3,8 @@ // #import "DataSource.h" +#import "TSContactThread.h" +#import "LKFriendRequestMessage.h" NS_ASSUME_NONNULL_BEGIN @@ -98,6 +100,7 @@ NS_SWIFT_NAME(MessageSender) failure:(void (^)(NSError *error))failureHandler; - (OWSMessageSend *)getSessionRestoreMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey; +- (LKFriendRequestMessage *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey inThread:(TSContactThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction; - (OWSMessageSend *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey; - (void)sendMessage:(OWSMessageSend *)messageSend; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 9d96edbfc..5b2c88a41 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -945,6 +945,22 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return [[OWSMessageSend alloc] initWithMessage:message thread:thread recipient:recipient senderCertificate:senderCertificate udAccess:theirUDAccess localNumber:userHexEncodedPublicKey success:^{ } failure:^(NSError *error) { }]; } +- (LKFriendRequestMessage *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey inThread:(TSContactThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + thread = [TSContactThread getOrCreateThreadWithContactId:hexEncodedPublicKey transaction:transaction]; + // Force hide slave device thread + NSString *masterHexEncodedPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:hexEncodedPublicKey in:transaction]; + thread.isForceHidden = masterHexEncodedPublicKey != nil && ![masterHexEncodedPublicKey isEqualToString:hexEncodedPublicKey]; + if (thread.friendRequestStatus == LKThreadFriendRequestStatusNone || thread.friendRequestStatus == LKThreadFriendRequestStatusRequestExpired) { + [thread saveFriendRequestStatus:LKThreadFriendRequestStatusRequestSent withTransaction:transaction]; + } + [thread saveWithTransaction:transaction]; + LKFriendRequestMessage *message = [[LKFriendRequestMessage alloc] initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"Please accept to enable messages to be synced across devices" attachmentIds:[NSMutableArray new] + expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil]; + message.skipSave = YES; + return message; +} + - (OWSMessageSend *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey { __block TSContactThread *thread; From ecf02bbb3e43896a729932c478d69ea1a476e48c Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 14 Feb 2020 11:37:14 +1100 Subject: [PATCH 06/19] fix sending contact sync messages --- SignalMessaging/contacts/OWSSyncManager.m | 2 +- SignalServiceKit/src/Messages/OWSMessageManager.m | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/SignalMessaging/contacts/OWSSyncManager.m b/SignalMessaging/contacts/OWSSyncManager.m index 8acbe1d45..0c673d497 100644 --- a/SignalMessaging/contacts/OWSSyncManager.m +++ b/SignalMessaging/contacts/OWSSyncManager.m @@ -279,7 +279,7 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag NSMutableArray *friends = @[].mutableCopy; [TSContactThread enumerateCollectionObjectsUsingBlock:^(TSContactThread *thread, BOOL *stop) { NSString *hexEncodedPublicKey = thread.contactIdentifier; - if (hexEncodedPublicKey != nil && thread.isContactFriend) { + if (hexEncodedPublicKey != nil && thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isForceHidden) { [friends addObject:[[SignalAccount alloc] initWithRecipientId:hexEncodedPublicKey]]; } }]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 1f136d051..2ee2dc0f9 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1035,6 +1035,7 @@ NS_ASSUME_NONNULL_BEGIN // acceptable. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[self.syncManager syncAllContacts] retainUntilComplete]; + [[self.syncManager syncAllGroups] retainUntilComplete]; }); } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeGroups) { OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init]; @@ -1090,6 +1091,7 @@ NS_ASSUME_NONNULL_BEGIN // [messageSender sendMessage:automatedFriendRequestMessage]; // }); LKFriendRequestMessage *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey inThread:thread transaction:transaction]; + [automatedFriendRequestMessage saveWithTransaction:transaction]; [self.messageSenderJobQueue addMessage:automatedFriendRequestMessage transaction:transaction]; break; } @@ -1113,7 +1115,7 @@ NS_ASSUME_NONNULL_BEGIN for (TSGroupModel *groupModel in groupModels) { TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; //TODO: Join the group and send update group information - [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; +// [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; } } } else { From 62cc2a399ff1150f69851bd96d260f0d7168e507 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 14 Feb 2020 13:46:45 +1100 Subject: [PATCH 07/19] totally fix the contact sync message issue --- SignalServiceKit/src/Messages/OWSMessageManager.m | 5 ----- SignalServiceKit/src/Messages/OWSMessageSender.m | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 399c4324c..0c1e38907 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1086,12 +1086,7 @@ NS_ASSUME_NONNULL_BEGIN switch (friendRequestStatus) { case LKThreadFriendRequestStatusNone: { OWSMessageSender *messageSender = SSKEnvironment.shared.messageSender; -// OWSMessageSend *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey]; -// dispatch_async(OWSDispatch.sendingQueue, ^{ -// [messageSender sendMessage:automatedFriendRequestMessage]; -// }); LKFriendRequestMessage *automatedFriendRequestMessage = [messageSender getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:hexEncodedPublicKey inThread:thread transaction:transaction]; - [automatedFriendRequestMessage saveWithTransaction:transaction]; [self.messageSenderJobQueue addMessage:automatedFriendRequestMessage transaction:transaction]; break; } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index f8a14ce9f..7e6e4573b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -958,6 +958,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; LKFriendRequestMessage *message = [[LKFriendRequestMessage alloc] initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp inThread:thread messageBody:@"Please accept to enable messages to be synced across devices" attachmentIds:[NSMutableArray new] expiresInSeconds:0 expireStartedAt:0 isVoiceMessage:NO groupMetaMessage:TSGroupMetaMessageUnspecified quotedMessage:nil contactShare:nil linkPreview:nil]; message.skipSave = YES; + [message saveWithTransaction:transaction]; return message; } From 171c2341b808c2babcf77d86f818c0118cb2d3b0 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 14 Feb 2020 14:54:06 +1100 Subject: [PATCH 08/19] join the group after receiving a group sync message --- .../src/Messages/OWSMessageManager.m | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 0998db963..b0e0ccbb4 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1108,9 +1108,35 @@ NS_ASSUME_NONNULL_BEGIN GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { - TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - //TODO: Join the group and send update group information -// [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; + NSMutableSet *members = [NSMutableSet setWithArray:groupModel.groupMemberIds]; + NSMutableSet *admins = [NSMutableSet setWithArray:groupModel.groupAdminIds]; + [members addObject:userHexEncodedPublicKey]; + if ([admins containsObject:masterHexEncodedPublicKey]) { + [admins addObject:userHexEncodedPublicKey]; + } + TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:groupModel.groupName + memberIds:members.allObjects + image:groupModel.groupImage + groupId:groupModel.groupId + groupType:groupModel.groupType + adminIds:admins.allObjects]; + NSString *updateGroupInfo = [groupModel getInfoStringAboutUpdateTo:newGroupModel contactsManager:self.contactsManager]; + TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:newGroupModel transaction:transaction]; + [thread saveWithTransaction:transaction]; + uint32_t expiresInSeconds = [thread disappearingMessagesDurationWithTransaction:transaction]; + TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:thread + groupMetaMessage:TSGroupMetaMessageUpdate + expiresInSeconds:expiresInSeconds]; + [message updateWithCustomMessage:updateGroupInfo transaction:transaction]; + OWSMessageSender *messageSender = SSKEnvironment.shared.messageSender; + [messageSender sendMessage:message + success:^{ + OWSLogDebug(@"Successfully sent group update for group sync"); + [self establishSessionsWithMembersIfNeeded:members.allObjects forThread:thread transaction:transaction]; + } + failure:^(NSError *error) { + OWSLogError(@"Failed to send group update for group sync with error: %@", error); + }]; } } } else { From d5c4939a45ef065645be6cdc16832eff47355008 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 09:19:25 +1100 Subject: [PATCH 09/19] enable leaving a closed group with linked device synced --- .../OWSIncomingSentMessageTranscript.h | 1 + .../OWSIncomingSentMessageTranscript.m | 1 + SignalServiceKit/src/Messages/OWSMessageManager.m | 14 ++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h index f31996d6b..87c8ea79e 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) uint64_t expirationStartedAt; @property (nonatomic, readonly) uint32_t expirationDuration; @property (nonatomic, readonly) BOOL isGroupUpdate; +@property (nonatomic, readonly) BOOL isGroupQuit; @property (nonatomic, readonly) BOOL isExpirationTimerUpdate; @property (nonatomic, readonly) BOOL isEndSessionMessage; @property (nonatomic, readonly, nullable) NSData *groupId; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m index d3218938a..994c1af86 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN _body = _dataMessage.body; _groupId = _dataMessage.group.id; _isGroupUpdate = _dataMessage.group != nil && (_dataMessage.group.type == SSKProtoGroupContextTypeUpdate); + _isGroupQuit = _dataMessage.group != nil && (_dataMessage.group.type == SSKProtoGroupContextTypeQuit); _isExpirationTimerUpdate = (_dataMessage.flags & SSKProtoDataMessageFlagsExpirationTimerUpdate) != 0; _isEndSessionMessage = (_dataMessage.flags & SSKProtoDataMessageFlagsEndSession) != 0; _isRecipientUpdate = sentProto.isRecipientUpdate; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index b0e0ccbb4..f2704bc6e 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1014,6 +1014,14 @@ NS_ASSUME_NONNULL_BEGIN messageType:TSInfoMessageTypeGroupUpdate customMessage:updateMessage]; [infoMessage saveWithTransaction:transaction]; + } 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]; } else { [OWSRecordTranscriptJob processIncomingSentMessageTranscript:transcript @@ -1108,14 +1116,12 @@ NS_ASSUME_NONNULL_BEGIN GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { - NSMutableSet *members = [NSMutableSet setWithArray:groupModel.groupMemberIds]; NSMutableSet *admins = [NSMutableSet setWithArray:groupModel.groupAdminIds]; - [members addObject:userHexEncodedPublicKey]; if ([admins containsObject:masterHexEncodedPublicKey]) { [admins addObject:userHexEncodedPublicKey]; } TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:groupModel.groupName - memberIds:members.allObjects + memberIds:groupModel.groupMemberIds image:groupModel.groupImage groupId:groupModel.groupId groupType:groupModel.groupType @@ -1132,7 +1138,7 @@ NS_ASSUME_NONNULL_BEGIN [messageSender sendMessage:message success:^{ OWSLogDebug(@"Successfully sent group update for group sync"); - [self establishSessionsWithMembersIfNeeded:members.allObjects forThread:thread transaction:transaction]; + [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; } failure:^(NSError *error) { OWSLogError(@"Failed to send group update for group sync with error: %@", error); From 41a630897394dff3612bc4c7b17ae302f67d5964 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 10:04:17 +1100 Subject: [PATCH 10/19] hide input tool bar on linked device after leaving a closed group --- SignalServiceKit/src/Contacts/Threads/TSGroupThread.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index 31f7cfaeb..5cd6125be 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -227,10 +227,13 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (void)leaveGroupWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - NSMutableArray *newGroupMemberIds = [self.groupModel.groupMemberIds mutableCopy]; - [newGroupMemberIds removeObject:[TSAccountManager localNumber]]; - - self.groupModel.groupMemberIds = newGroupMemberIds; + NSMutableSet *newGroupMemberIds = [NSMutableSet setWithArray:self.groupModel.groupMemberIds]; + NSString *userHexEncodedPublicKey = TSAccountManager.localNumber; + if (userHexEncodedPublicKey != nil) { + NSSet *linkedDeviceHexEncodedPublicKeys = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:userHexEncodedPublicKey in:transaction]; + [newGroupMemberIds minusSet:linkedDeviceHexEncodedPublicKeys]; + } + self.groupModel.groupMemberIds = newGroupMemberIds.allObjects; [self saveWithTransaction:transaction]; } From a3cd1995cd8562163cf452b00732547458228867 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 10:12:40 +1100 Subject: [PATCH 11/19] update the handler of receiving a sync request for groups --- .../src/Messages/OWSMessageManager.m | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index ea70403e7..1e74b6a54 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1053,23 +1053,11 @@ NS_ASSUME_NONNULL_BEGIN // acceptable. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[self.syncManager syncAllContacts] retainUntilComplete]; - [[self.syncManager syncAllGroups] retainUntilComplete]; }); } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeGroups) { - OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init]; - NSData *_Nullable syncData = [syncGroupsMessage buildPlainTextAttachmentDataWithTransaction:transaction]; - if (!syncData) { - OWSFailDebug(@"Failed to serialize groups sync message."); - return; - } - DataSource *dataSource = [DataSourceValue dataSourceWithSyncMessageData:syncData]; - [self.messageSenderJobQueue addMediaMessage:syncGroupsMessage - dataSource:dataSource - contentType:OWSMimeTypeApplicationOctetStream - sourceFilename:nil - caption:nil - albumMessageId:nil - isTemporaryAttachment:YES]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[self.syncManager syncAllGroups] retainUntilComplete]; + }); } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeBlocked) { OWSLogInfo(@"Received request for block list"); [self.blockingManager syncBlockList]; From c3c080eb59d21fb6843253153a59fcec226b6d0b Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 10:58:42 +1100 Subject: [PATCH 12/19] add linked device to admins --- Signal/src/Loki/View Controllers/NewClosedGroupVC.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index 661dedf63..260ddc304 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -169,7 +169,10 @@ final class NewClosedGroupVC : UIViewController, UITableViewDataSource, UITableV } let userHexEncodedPublicKey = getUserHexEncodedPublicKey() let members = [String](selectedContacts) + [ userHexEncodedPublicKey ] - let admins = [ userHexEncodedPublicKey ] + var admins: [String]! + OWSPrimaryStorage.shared().dbReadConnection.readWrite { transaction in + admins = Array(LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: userHexEncodedPublicKey, in: transaction)) + } let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(Randomness.generateRandomBytes(kGroupIdLength)!.toHexString()) let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) let thread = TSGroupThread.getOrCreateThread(with: group) From 7bafd94643819150fbb8d588d40b8ec0374565e6 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 10:59:25 +1100 Subject: [PATCH 13/19] check if the linked device is a member of the closed group --- SignalServiceKit/src/Contacts/Threads/TSGroupThread.h | 1 + SignalServiceKit/src/Contacts/Threads/TSGroupThread.m | 7 +++++++ SignalServiceKit/src/Messages/OWSMessageManager.m | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h index 4b614371f..d0b5047e8 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h @@ -38,6 +38,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; - (BOOL)isLocalUserInGroup; - (BOOL)isLocalUserInGroupWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (BOOL)isUserInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction; // all group threads containing recipient as a member + (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index 5cd6125be..2ddaae043 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -204,6 +204,13 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupMemberIds]]; } +- (BOOL)isUserInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + if (hexEncodedPublicKey == nil) { return NO; } + NSSet *linkedDeviceHexEncodedPublicKeys = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:hexEncodedPublicKey in:transaction]; + return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupMemberIds]]; +} + - (NSString *)name { // TODO sometimes groupName is set to the empty string. I'm hesitent to change diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 1e74b6a54..089395b37 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1360,7 +1360,7 @@ NS_ASSUME_NONNULL_BEGIN } // Ensure sender is in the group. - if (![gThread.groupModel.groupMemberIds containsObject:envelope.source]) { + if (![gThread isUserInGroup:envelope.source transaction:transaction]) { OWSLogWarn(@"Ignoring 'Request Group Info' message for non-member of group. %@ not in %@", envelope.source, gThread.groupModel.groupMemberIds); From 7d66fa151c5b300cadc4b6f62454630cea4fcaa4 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 17 Feb 2020 13:33:09 +1100 Subject: [PATCH 14/19] fix admin check method --- .../ThreadSettings/UpdateGroupViewController.m | 1 - SignalServiceKit/src/Contacts/Threads/TSGroupThread.h | 1 + SignalServiceKit/src/Contacts/Threads/TSGroupThread.m | 7 +++++++ SignalServiceKit/src/Messages/OWSMessageManager.m | 4 +++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m b/Signal/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m index 6da77bb3b..a55c240d2 100644 --- a/Signal/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m +++ b/Signal/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m @@ -385,7 +385,6 @@ NS_ASSUME_NONNULL_BEGIN groupId:self.thread.groupModel.groupId groupType:self.thread.groupModel.groupType adminIds:self.thread.groupModel.groupAdminIds]; - groupModel.removedMembers = self.removedRecipientIds; [self.conversationSettingsViewDelegate groupWasUpdated:groupModel]; } diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h index d0b5047e8..a243daa7f 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h @@ -39,6 +39,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; - (BOOL)isLocalUserInGroup; - (BOOL)isLocalUserInGroupWithTransaction:(YapDatabaseReadTransaction *)transaction; - (BOOL)isUserInGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction; +- (BOOL)isUserAdminForGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction; // all group threads containing recipient as a member + (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index 2ddaae043..98b80ecc3 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -211,6 +211,13 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupMemberIds]]; } +- (BOOL)isUserAdminForGroup:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + if (hexEncodedPublicKey == nil) { return NO; } + NSSet *linkedDeviceHexEncodedPublicKeys = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:hexEncodedPublicKey in:transaction]; + return [linkedDeviceHexEncodedPublicKeys intersectsSet:[NSSet setWithArray:self.groupModel.groupAdminIds]]; +} + - (NSString *)name { // TODO sometimes groupName is set to the empty string. I'm hesitent to change diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 089395b37..2585fbf90 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1024,6 +1024,8 @@ NS_ASSUME_NONNULL_BEGIN messageType:TSInfoMessageTypeGroupUpdate customMessage:updateMessage]; [infoMessage saveWithTransaction:transaction]; + // Loki: if there is a update of group members, we should establish a session with the new members. + [self establishSessionsWithMembersIfNeeded:newGroupModel.groupMemberIds forThread:newGroupThread transaction:transaction]; } else if (transcript.isGroupQuit) { TSGroupThread *groupThread = [TSGroupThread getOrCreateThreadWithGroupId:transcript.dataMessage.group.id groupType:closedGroup transaction:transaction]; [groupThread leaveGroupWithTransaction:transaction]; @@ -1477,7 +1479,7 @@ NS_ASSUME_NONNULL_BEGIN switch (dataMessage.group.type) { case SSKProtoGroupContextTypeUpdate: { - if (oldGroupThread && ![oldGroupThread.groupModel.groupAdminIds containsObject:hexEncodedPublicKey]) { + if (oldGroupThread && ![oldGroupThread isUserAdminForGroup:hexEncodedPublicKey transaction:transaction]) { [LKLogger print:[NSString stringWithFormat:@"[Loki] Received a group update from a non-admin user for %@; ignoring.", [LKGroupUtilities getEncodedGroupID:groupId]]]; return nil; } From a245595bc5eafc44e27700541c3d63f480c954e6 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Tue, 18 Feb 2020 14:01:48 +1100 Subject: [PATCH 15/19] use master public key instead of user public key when adding self as a member and an admin --- .../src/Loki/View Controllers/NewClosedGroupVC.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index 260ddc304..6d9159b52 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -168,11 +168,14 @@ final class NewClosedGroupVC : UIViewController, UITableViewDataSource, UITableV return showError(title: NSLocalizedString("A closed group cannot have more than 10 members", comment: "")) } let userHexEncodedPublicKey = getUserHexEncodedPublicKey() - let members = [String](selectedContacts) + [ userHexEncodedPublicKey ] - var admins: [String]! - OWSPrimaryStorage.shared().dbReadConnection.readWrite { transaction in - admins = Array(LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: userHexEncodedPublicKey, in: transaction)) + let storage = OWSPrimaryStorage.shared() + var masterHexEncodedPublicKey = "" + storage.dbReadConnection.readWrite { transaction in + masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: userHexEncodedPublicKey, in: transaction) ?? userHexEncodedPublicKey } + let members = [String](selectedContacts) + [ masterHexEncodedPublicKey ] + let admins = [ masterHexEncodedPublicKey ] + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(Randomness.generateRandomBytes(kGroupIdLength)!.toHexString()) let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) let thread = TSGroupThread.getOrCreateThread(with: group) From 87b7bfa0c011e009c3ccc2e7baa5b702e89f2421 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Tue, 18 Feb 2020 14:02:51 +1100 Subject: [PATCH 16/19] remove updating for admins after a slave device received a group sync message --- .../src/Messages/OWSMessageManager.m | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index e3382d71e..852964732 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1112,33 +1112,9 @@ NS_ASSUME_NONNULL_BEGIN GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { - NSMutableSet *admins = [NSMutableSet setWithArray:groupModel.groupAdminIds]; - if ([admins containsObject:masterHexEncodedPublicKey]) { - [admins addObject:userHexEncodedPublicKey]; - } - TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:groupModel.groupName - memberIds:groupModel.groupMemberIds - image:groupModel.groupImage - groupId:groupModel.groupId - groupType:groupModel.groupType - adminIds:admins.allObjects]; - NSString *updateGroupInfo = [groupModel getInfoStringAboutUpdateTo:newGroupModel contactsManager:self.contactsManager]; - TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:newGroupModel transaction:transaction]; + TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; [thread saveWithTransaction:transaction]; - uint32_t expiresInSeconds = [thread disappearingMessagesDurationWithTransaction:transaction]; - TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:thread - groupMetaMessage:TSGroupMetaMessageUpdate - expiresInSeconds:expiresInSeconds]; - [message updateWithCustomMessage:updateGroupInfo transaction:transaction]; - OWSMessageSender *messageSender = SSKEnvironment.shared.messageSender; - [messageSender sendMessage:message - success:^{ - OWSLogDebug(@"Successfully sent group update for group sync"); - [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; - } - failure:^(NSError *error) { - OWSLogError(@"Failed to send group update for group sync with error: %@", error); - }]; + [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; } } } else { From 5c3c00243cf267e8461a255bd5f0892f950cd737 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 21 Feb 2020 15:11:07 +1100 Subject: [PATCH 17/19] send sync messages with 2 contacts and 1 group each time --- Signal/Signal-Info.plist | 2 +- ...nversationConfigurationSyncOperation.swift | 2 +- .../View Controllers/DeviceLinkingModal.swift | 2 +- .../DebugUI/DebugUISyncMessages.m | 15 +-------- SignalMessaging/contacts/OWSSyncManager.m | 24 ++++++++++++-- .../DeviceSyncing/OWSSyncGroupsMessage.h | 6 +++- .../DeviceSyncing/OWSSyncGroupsMessage.m | 33 +++++++++---------- 7 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 342d37adb..9d7c02e10 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -7,7 +7,7 @@ CarthageVersion 0.34.0 OSXVersion - 10.15.3 + 10.15.2 WebRTCCommit 1445d719bf05280270e9f77576f80f973fd847f8 M73 diff --git a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift index 783c8af68..0a47382b7 100644 --- a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift +++ b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift @@ -64,7 +64,7 @@ class ConversationConfigurationSyncOperation: OWSOperation { // The current implementation works, but seems wasteful. // Does desktop handle single group sync correctly? // What does Android do? - let syncMessage: OWSSyncGroupsMessage = OWSSyncGroupsMessage() + let syncMessage: OWSSyncGroupsMessage = OWSSyncGroupsMessage(groupThread: groupThread) var dataSource: DataSource? self.dbConnection.read { transaction in diff --git a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift index ba52bcf11..b2a304ea3 100644 --- a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift +++ b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift @@ -166,7 +166,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { ThreadUtil.enqueue(linkingAuthorizationMessage) SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: { let _ = SSKEnvironment.shared.syncManager.syncAllContacts() - _ = SSKEnvironment.shared.syncManager.syncAllGroups() +// _ = SSKEnvironment.shared.syncManager.syncAllGroups() }) { _ in print("[Loki] Failed to send device link authorization message.") } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m index cc493cd89..124f14c86 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m @@ -108,20 +108,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)sendGroupSyncMessage { - OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init]; - __block DataSource *dataSource; - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - dataSource = [DataSourceValue - dataSourceWithSyncMessageData:[syncGroupsMessage buildPlainTextAttachmentDataWithTransaction:transaction]]; - }]; - - [self.messageSenderJobQueue addMediaMessage:syncGroupsMessage - dataSource:dataSource - contentType:OWSMimeTypeApplicationOctetStream - sourceFilename:nil - caption:nil - albumMessageId:nil - isTemporaryAttachment:YES]; + [[self.syncManager syncAllGroups] retainUntilComplete]; } + (void)sendBlockListSyncMessage diff --git a/SignalMessaging/contacts/OWSSyncManager.m b/SignalMessaging/contacts/OWSSyncManager.m index ba406ca04..4c4df6d87 100644 --- a/SignalMessaging/contacts/OWSSyncManager.m +++ b/SignalMessaging/contacts/OWSSyncManager.m @@ -23,6 +23,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -281,13 +282,21 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag - (AnyPromise *)syncAllContacts { NSMutableArray *friends = @[].mutableCopy; + NSMutableArray *promises = @[].mutableCopy; [TSContactThread enumerateCollectionObjectsUsingBlock:^(TSContactThread *thread, BOOL *stop) { NSString *hexEncodedPublicKey = thread.contactIdentifier; if (hexEncodedPublicKey != nil && thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isForceHidden) { [friends addObject:[[SignalAccount alloc] initWithRecipientId:hexEncodedPublicKey]]; } + if (friends.count >= 2) { + [promises addObject:[self syncContactsForSignalAccounts:friends]]; + [friends removeAllObjects]; + } }]; - return [self syncContactsForSignalAccounts:friends]; + if (friends.count > 0) { + [promises addObject:[self syncContactsForSignalAccounts:friends]]; + } + return PMKJoin(promises); } - (AnyPromise *)syncContactsForSignalAccounts:(NSArray *)signalAccounts @@ -310,7 +319,18 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag - (AnyPromise *)syncAllGroups { - OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] init]; + NSMutableArray *promises = @[].mutableCopy; + [TSGroupThread enumerateCollectionObjectsUsingBlock:^(TSGroupThread *thread, BOOL *stop) { + if (thread.groupModel && thread.shouldThreadBeVisible && !thread.isForceHidden) { + [promises addObject:[self syncGroupForThread:thread]]; + } + }]; + return PMKJoin(promises); +} + +- (AnyPromise *)syncGroupForThread:(TSGroupThread *)thread +{ + OWSSyncGroupsMessage *syncGroupsMessage = [[OWSSyncGroupsMessage alloc] initWithGroupThread:thread]; AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { [self.messageSender sendMessage:syncGroupsMessage success:^{ diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h index 7f5ba902f..6f7ccc188 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h @@ -7,10 +7,14 @@ NS_ASSUME_NONNULL_BEGIN @class YapDatabaseReadTransaction; +@class TSGroupThread; @interface OWSSyncGroupsMessage : OWSOutgoingSyncMessage -- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithGroupThread:(TSGroupThread *)thread NS_DESIGNATED_INITIALIZER; + - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; - (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m index 5bce40231..9ee62dd34 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m @@ -15,11 +15,24 @@ NS_ASSUME_NONNULL_BEGIN +@interface OWSSyncGroupsMessage () + +@property (nonatomic, readonly) TSGroupThread *groupThread; + +@end + @implementation OWSSyncGroupsMessage -- (instancetype)init +- (instancetype)initWithGroupThread:(TSGroupThread *)thread { - return [super init]; + self = [super init]; + if (!self) { + return self; + } + + _groupThread = thread; + + return self; } - (nullable instancetype)initWithCoder:(NSCoder *)coder @@ -75,21 +88,7 @@ NS_ASSUME_NONNULL_BEGIN NSOutputStream *dataOutputStream = [NSOutputStream outputStreamToMemory]; [dataOutputStream open]; OWSGroupsOutputStream *groupsOutputStream = [[OWSGroupsOutputStream alloc] initWithOutputStream:dataOutputStream]; - - [TSGroupThread - enumerateCollectionObjectsWithTransaction:transaction - usingBlock:^(id obj, BOOL *stop) { - if (![obj isKindOfClass:[TSGroupThread class]] || ((TSGroupThread *)obj).groupModel.groupType != closedGroup) { - if (![obj isKindOfClass:[TSContactThread class]]) { - OWSLogWarn( - @"Ignoring non group thread in thread collection: %@", obj); - } - return; - } - TSGroupThread *groupThread = (TSGroupThread *)obj; - [groupsOutputStream writeGroup:groupThread transaction:transaction]; - }]; - + [groupsOutputStream writeGroup:self.groupThread transaction:transaction]; [dataOutputStream close]; if (groupsOutputStream.hasError) { From dfa238a287b0bf1a893c2fdb19fc6804e22569b7 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Mon, 24 Feb 2020 11:52:54 +1100 Subject: [PATCH 18/19] wip: fix sync message --- Signal/Signal-Info.plist | 2 +- .../View Controllers/DeviceLinkingModal.swift | 4 +-- SignalMessaging/contacts/OWSSyncManager.m | 32 +++++++++++++------ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index c49053bcc..9d7c02e10 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -5,7 +5,7 @@ BuildDetails CarthageVersion - 0.33.0 + 0.34.0 OSXVersion 10.15.2 WebRTCCommit diff --git a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift index b2a304ea3..195dd5669 100644 --- a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift +++ b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift @@ -165,8 +165,8 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { let linkingAuthorizationMessage = DeviceLinkingUtilities.getLinkingAuthorizationMessage(for: deviceLink) ThreadUtil.enqueue(linkingAuthorizationMessage) SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: { - let _ = SSKEnvironment.shared.syncManager.syncAllContacts() -// _ = SSKEnvironment.shared.syncManager.syncAllGroups() + let _ = [SSKEnvironment.shared.syncManager.syncAllContacts(), + SSKEnvironment.shared.syncManager.syncAllGroups()] }) { _ in print("[Loki] Failed to send device link authorization message.") } diff --git a/SignalMessaging/contacts/OWSSyncManager.m b/SignalMessaging/contacts/OWSSyncManager.m index 4c4df6d87..2ebbc95ee 100644 --- a/SignalMessaging/contacts/OWSSyncManager.m +++ b/SignalMessaging/contacts/OWSSyncManager.m @@ -288,15 +288,21 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag if (hexEncodedPublicKey != nil && thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isForceHidden) { [friends addObject:[[SignalAccount alloc] initWithRecipientId:hexEncodedPublicKey]]; } - if (friends.count >= 2) { - [promises addObject:[self syncContactsForSignalAccounts:friends]]; - [friends removeAllObjects]; - } }]; - if (friends.count > 0) { - [promises addObject:[self syncContactsForSignalAccounts:friends]]; + NSMutableArray *signalAccounts = @[].mutableCopy; + for (SignalAccount *contact in friends) { + [signalAccounts addObject:contact]; + if (signalAccounts.count >= 2) { + [promises addObject:[self syncContactsForSignalAccounts:signalAccounts]]; + [signalAccounts removeAllObjects]; + } } - return PMKJoin(promises); + if (signalAccounts.count > 0) { + [promises addObject:[self syncContactsForSignalAccounts:signalAccounts]]; + } + AnyPromise *promise = PMKJoin(promises); + [promise retainUntilComplete]; + return promise; } - (AnyPromise *)syncContactsForSignalAccounts:(NSArray *)signalAccounts @@ -319,13 +325,19 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag - (AnyPromise *)syncAllGroups { + NSMutableArray *groupThreads = @[].mutableCopy; NSMutableArray *promises = @[].mutableCopy; [TSGroupThread enumerateCollectionObjectsUsingBlock:^(TSGroupThread *thread, BOOL *stop) { - if (thread.groupModel && thread.shouldThreadBeVisible && !thread.isForceHidden) { - [promises addObject:[self syncGroupForThread:thread]]; + if (thread.groupModel.groupType == closedGroup && thread.shouldThreadBeVisible && !thread.isForceHidden) { + [groupThreads addObject:thread]; } }]; - return PMKJoin(promises); + for (TSGroupThread *groupThread in groupThreads) { + [promises addObject:[self syncGroupForThread:groupThread]]; + } + AnyPromise *promise = PMKJoin(promises); + [promise retainUntilComplete]; + return promise; } - (AnyPromise *)syncGroupForThread:(TSGroupThread *)thread From 9afd838ea50b49c5ea588bd8d48e7784238f0ec1 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Tue, 25 Feb 2020 10:34:59 +1100 Subject: [PATCH 19/19] fix the sync message bug after refactoring --- Pods | 2 +- SignalMessaging/contacts/OWSSyncManager.m | 15 ++++++++++++--- .../src/Loki/Messaging/ContactParser.swift | 2 +- .../DeviceSyncing/OWSSyncContactsMessage.m | 15 --------------- .../src/Messages/OWSMessageDecrypter.m | 2 +- .../src/Messages/OWSMessageManager.m | 16 +++++++++++----- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Pods b/Pods index 2870e676d..67dbced37 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 2870e676deec6a7ddb931edb6f0284f1f5b36085 +Subproject commit 67dbced37481e0011a3df1397ed57711384a4957 diff --git a/SignalMessaging/contacts/OWSSyncManager.m b/SignalMessaging/contacts/OWSSyncManager.m index 2ebbc95ee..d5c2c4574 100644 --- a/SignalMessaging/contacts/OWSSyncManager.m +++ b/SignalMessaging/contacts/OWSSyncManager.m @@ -289,11 +289,12 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag [friends addObject:[[SignalAccount alloc] initWithRecipientId:hexEncodedPublicKey]]; } }]; + [friends addObject:[[SignalAccount alloc] initWithRecipientId:self.tsAccountManager.localNumber]]; NSMutableArray *signalAccounts = @[].mutableCopy; for (SignalAccount *contact in friends) { [signalAccounts addObject:contact]; - if (signalAccounts.count >= 2) { - [promises addObject:[self syncContactsForSignalAccounts:signalAccounts]]; + if (signalAccounts.count >= 3) { + [promises addObject:[self syncContactsForSignalAccounts:[signalAccounts copy]]]; [signalAccounts removeAllObjects]; } } @@ -327,7 +328,15 @@ NSString *const kSyncManagerLastContactSyncKey = @"kTSStorageManagerOWSSyncManag { NSMutableArray *groupThreads = @[].mutableCopy; NSMutableArray *promises = @[].mutableCopy; - [TSGroupThread enumerateCollectionObjectsUsingBlock:^(TSGroupThread *thread, BOOL *stop) { + [TSGroupThread enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) { + if (![obj isKindOfClass:[TSGroupThread class]]) { + if (![obj isKindOfClass:[TSContactThread class]]) { + OWSLogWarn(@"Ignoring non group thread in thread collection: %@", obj); + + } + return; + } + TSGroupThread *thread = (TSGroupThread *)obj; if (thread.groupModel.groupType == closedGroup && thread.shouldThreadBeVisible && !thread.isForceHidden) { [groupThreads addObject:thread]; } diff --git a/SignalServiceKit/src/Loki/Messaging/ContactParser.swift b/SignalServiceKit/src/Loki/Messaging/ContactParser.swift index 7b3dea666..b29e9c218 100644 --- a/SignalServiceKit/src/Loki/Messaging/ContactParser.swift +++ b/SignalServiceKit/src/Loki/Messaging/ContactParser.swift @@ -17,7 +17,7 @@ guard let size = uncheckedSize, size < data.count else { break } let sizeAsInt = Int(size) index += 4 - guard index + sizeAsInt < data.count else { break } + guard index + sizeAsInt <= data.count else { break } let protoAsData = data[index..<(index+sizeAsInt)] guard let proto = try? SSKProtoContactDetails.parseData(protoAsData) else { break } index += sizeAsInt diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m index 19bd4263c..2e67f3996 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m @@ -109,21 +109,6 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSData *)buildPlainTextAttachmentDataWithTransaction:(YapDatabaseReadTransaction *)transaction { NSMutableArray *signalAccounts = [self.signalAccounts mutableCopy]; - - NSString *_Nullable localNumber = self.tsAccountManager.localNumber; - OWSAssertDebug(localNumber); - if (localNumber) { - BOOL hasLocalNumber = NO; - for (SignalAccount *signalAccount in signalAccounts) { - hasLocalNumber |= [signalAccount.recipientId isEqualToString:localNumber]; - } - if (!hasLocalNumber) { - SignalAccount *signalAccount = [[SignalAccount alloc] initWithRecipientId:localNumber]; - // OWSContactsOutputStream requires all signalAccount to have a contact. - signalAccount.contact = [[Contact alloc] initWithSystemContact:[CNContact new]]; - [signalAccounts addObject:signalAccount]; - } - } // TODO use temp file stream to avoid loading everything into memory at once // First though, we need to re-engineer our attachment process to accept streams (encrypting with stream, diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index 24b45947a..aba11134a 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -431,7 +431,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes sessionStore:self.primaryStorage preKeyStore:self.primaryStorage signedPreKeyStore:self.primaryStorage - identityKeyStore:self.primaryStorage + identityKeyStore:self.identityManager recipientID:recipientId deviceID:deviceId]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 3a72a6de0..70da59c56 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1020,8 +1020,6 @@ NS_ASSUME_NONNULL_BEGIN messageType:TSInfoMessageTypeGroupUpdate customMessage:updateMessage]; [infoMessage saveWithTransaction:transaction]; - // Loki: if there is a update of group members, we should establish a session with the new members. - [self establishSessionsWithMembersIfNeeded:newGroupModel.groupMemberIds forThread:newGroupThread transaction:transaction]; } else if (transcript.isGroupQuit) { TSGroupThread *groupThread = [TSGroupThread getOrCreateThreadWithGroupId:transcript.dataMessage.group.id groupType:closedGroup transaction:transaction]; [groupThread leaveGroupWithTransaction:transaction]; @@ -1112,9 +1110,17 @@ NS_ASSUME_NONNULL_BEGIN GroupParser *parser = [[GroupParser alloc] initWithData:data]; NSArray *groupModels = [parser parseGroupModels]; for (TSGroupModel *groupModel in groupModels) { - TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - [thread saveWithTransaction:transaction]; - [self establishSessionsWithMembersIfNeeded:groupModel.groupMemberIds forThread:thread transaction:transaction]; + 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]; + } } } } else {