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); + 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); } - - SSKProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; - if (!attachmentProto) { - OWSFailDebug(@"could not build protobuf."); - return nil; + + 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]; } - SSKProtoSyncMessageGroupsBuilder *groupsBuilder = [SSKProtoSyncMessageGroups builder]; - [groupsBuilder setBlob:attachmentProto]; - - NSError *error; 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