From 32814b022762b4a65ed479a2eec1c8aa75cdf0d4 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 9 Jul 2020 09:18:23 +1000 Subject: [PATCH] Update for protocol changes --- SignalServiceKit/protobuf/SignalService.proto | 14 +-- .../Closed Groups/ClosedGroupSenderKey.swift | 10 +- .../ClosedGroupUpdateMessage.swift | 23 +++-- .../Closed Groups/ClosedGroupsProtocol.swift | 94 ++++++++++++++++--- .../Closed Groups/Storage+ClosedGroups.swift | 2 +- .../Sync Messages/SyncMessagesProtocol.swift | 6 +- .../src/Protos/Generated/SSKProto.swift | 27 +++--- .../Protos/Generated/SignalService.pb.swift | 36 ++++--- 8 files changed, 151 insertions(+), 61 deletions(-) diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index 64a1505b0..de4cb009e 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -243,9 +243,11 @@ message DataMessage { message ClosedGroupUpdate { // Loki enum Type { - NEW = 0; // groupPublicKey, name, groupPrivateKey, senderKeys, members, admins - INFO = 1; // groupPublicKey, name, senderKeys, members, admins - SENDER_KEY = 2; // groupPublicKey, senderKeys + NEW = 0; // groupPublicKey, name, groupPrivateKey, senderKeys, members, admins + INFO = 1; // groupPublicKey, name, senderKeys, members, admins + SENDER_KEY_REQUEST = 2; // groupPublicKey + SENDER_KEY = 3; // groupPublicKey, senderKeys + } message SenderKey { @@ -254,7 +256,7 @@ message DataMessage { // @required optional uint32 keyIndex = 2; // @required - optional string publicKey = 3; + optional bytes publicKey = 3; } optional string name = 1; @@ -262,8 +264,8 @@ message DataMessage { optional bytes groupPublicKey = 2; optional bytes groupPrivateKey = 3; repeated SenderKey senderKeys = 4; - repeated string members = 5; - repeated string admins = 6; + repeated bytes members = 5; + repeated bytes admins = 6; // @required optional Type type = 7; } diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupSenderKey.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupSenderKey.swift index 9c6c16d27..e29fda01e 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupSenderKey.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupSenderKey.swift @@ -2,10 +2,10 @@ internal final class ClosedGroupSenderKey : NSObject, NSCoding { internal let chainKey: Data internal let keyIndex: UInt - internal let publicKey: String + internal let publicKey: Data // MARK: Initialization - init(chainKey: Data, keyIndex: UInt, publicKey: String) { + init(chainKey: Data, keyIndex: UInt, publicKey: Data) { self.chainKey = chainKey self.keyIndex = keyIndex self.publicKey = publicKey @@ -15,7 +15,7 @@ internal final class ClosedGroupSenderKey : NSObject, NSCoding { public init?(coder: NSCoder) { guard let chainKey = coder.decodeObject(forKey: "chainKey") as? Data, let keyIndex = coder.decodeObject(forKey: "keyIndex") as? UInt, - let publicKey = coder.decodeObject(forKey: "publicKey") as? String else { return nil } + let publicKey = coder.decodeObject(forKey: "publicKey") as? Data else { return nil } self.chainKey = chainKey self.keyIndex = UInt(keyIndex) self.publicKey = publicKey @@ -45,5 +45,7 @@ internal final class ClosedGroupSenderKey : NSObject, NSCoding { } // MARK: Description - override public var description: String { return "[ chainKey : \(chainKey), keyIndex : \(keyIndex), publicKey: \(publicKey) ]" } + override public var description: String { + return "[ chainKey : \(chainKey), keyIndex : \(keyIndex), publicKey: \(publicKey.toHexString()) ]" + } } diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift index 61867f103..0d560f824 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift @@ -11,8 +11,9 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { // MARK: Kind internal enum Kind { - case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [String], admins: [String]) - case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [String], admins: [String]) + case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) + case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) + case senderKeyRequest(groupPublicKey: Data, members: [Data]) case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey) } @@ -39,14 +40,18 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { case "new": guard let name = coder.decodeObject(forKey: "name") as? String, let groupPrivateKey = coder.decodeObject(forKey: "groupPrivateKey") as? Data, - let members = coder.decodeObject(forKey: "members") as? [String], - let admins = coder.decodeObject(forKey: "admins") as? [String] else { return nil } + let members = coder.decodeObject(forKey: "members") as? [Data], + let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return nil } self.kind = .new(groupPublicKey: groupPublicKey, name: name, groupPrivateKey: groupPrivateKey, senderKeys: senderKeys, members: members, admins: admins) case "info": guard let name = coder.decodeObject(forKey: "name") as? String, - let members = coder.decodeObject(forKey: "members") as? [String], - let admins = coder.decodeObject(forKey: "admins") as? [String] else { return nil } + let members = coder.decodeObject(forKey: "members") as? [Data], + let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return nil } self.kind = .info(groupPublicKey: groupPublicKey, name: name, senderKeys: senderKeys, members: members, admins: admins) + case "senderKeyRequest": + guard let name = coder.decodeObject(forKey: "name") as? String, + let members = coder.decodeObject(forKey: "members") as? [Data] else { return nil } + self.kind = .senderKeyRequest(groupPublicKey: groupPublicKey, members: members) case "senderKey": guard let senderKey = senderKeys.first else { return nil } self.kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: senderKey) @@ -76,6 +81,9 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { coder.encode(senderKeys, forKey: "senderKeys") coder.encode(members, forKey: "members") coder.encode(admins, forKey: "admins") + case .senderKeyRequest(let groupPublicKey, let members): + coder.encode(groupPublicKey, forKey: "groupPublicKey") + coder.encode(members, forKey: "members") case .senderKey(let groupPublicKey, let senderKey): coder.encode("senderKey", forKey: "kind") coder.encode(groupPublicKey, forKey: "groupPublicKey") @@ -102,6 +110,9 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() }) closedGroupUpdate.setMembers(members) closedGroupUpdate.setAdmins(admins) + case .senderKeyRequest(let groupPublicKey, let members): + closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKeyRequest) + closedGroupUpdate.setMembers(members) case .senderKey(let groupPublicKey, let senderKey): closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKey) closedGroupUpdate.setSenderKeys([ try senderKey.toProto() ]) diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index 1588ab137..afef95ed5 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -27,6 +27,7 @@ public final class ClosedGroupsProtocol : NSObject { // Ensure the current user's master device is the one that's included in the member list members.remove(userPublicKey) members.insert(UserDefaults.standard[.masterHexEncodedPublicKey] ?? userPublicKey) + let membersAsData = members.map { Data(hex: $0) } // Create ratchets for all members (and their linked devices) var membersAndLinkedDevices: Set = members for member in members { @@ -35,10 +36,11 @@ public final class ClosedGroupsProtocol : NSObject { } let senderKeys: [ClosedGroupSenderKey] = membersAndLinkedDevices.map { publicKey in let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: publicKey) + return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Create the group let admins = [ UserDefaults.standard[.masterHexEncodedPublicKey] ?? userPublicKey ] + let adminsAsData = admins.map { Data(hex: $0) } let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let group = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction) @@ -53,7 +55,7 @@ public final class ClosedGroupsProtocol : NSObject { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: [String](members), admins: admins) + groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: membersAsData, admins: adminsAsData) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) promises.append(SSKEnvironment.shared.messageSender.sendPromise(message: closedGroupUpdateMessage)) } @@ -76,12 +78,14 @@ public final class ClosedGroupsProtocol : NSObject { let group = thread.groupModel let name = group.groupName! let admins = group.groupAdminIds + let adminsAsData = admins.map { Data(hex: $0) } guard let groupPrivateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey) else { return print("[Loki] Can't get private key for closed group.") } // Add the members to the member list var members = group.groupMemberIds members.append(contentsOf: newMembers) + let membersAsData = members.map { Data(hex: $0) } // Generate ratchets for the new members (and their linked devices) var newMembersAndLinkedDevices: Set = newMembers for member in newMembers { @@ -90,11 +94,11 @@ public final class ClosedGroupsProtocol : NSObject { } let senderKeys: [ClosedGroupSenderKey] = newMembersAndLinkedDevices.map { publicKey in let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: publicKey) + return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Send a closed group update message to the existing members with the new members' ratchets (this message is aimed at the group) let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: senderKeys, - members: members, admins: admins) + members: membersAsData, admins: adminsAsData) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // Establish sessions if needed @@ -106,7 +110,7 @@ public final class ClosedGroupsProtocol : NSObject { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, - groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: members, admins: admins) + groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) } @@ -138,6 +142,7 @@ public final class ClosedGroupsProtocol : NSObject { let group = thread.groupModel let name = group.groupName! let admins = group.groupAdminIds + let adminsAsData = admins.map { Data(hex: $0) } // Remove the members from the member list var members = group.groupMemberIds let indexes = membersToRemove.compactMap { members.firstIndex(of: $0) } @@ -145,9 +150,10 @@ public final class ClosedGroupsProtocol : NSObject { return print("[Loki] Can't remove users from group.") } indexes.forEach { members.remove(at: $0) } + let membersAsData = members.map { Data(hex: $0) } // Send the update to the group (don't include new ratchets as everyone should generate new ratchets individually) let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], - members: members, admins: admins) + members: membersAsData, admins: adminsAsData) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // Delete all ratchets (it's important that this happens after sending out the update) @@ -162,7 +168,7 @@ public final class ClosedGroupsProtocol : NSObject { // Send out the user's new ratchet to all members (minus the removed ones) and their linked devices using established channels let userPublicKey = getUserHexEncodedPublicKey() let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: userPublicKey) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { // This internally takes care of multi device let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) @@ -188,6 +194,7 @@ public final class ClosedGroupsProtocol : NSObject { switch closedGroupUpdate.type { case .new: handleNewGroupMessage(closedGroupUpdate, using: transaction) case .info: handleInfoMessage(closedGroupUpdate, from: publicKey, using: transaction) + case .senderKeyRequest: handleSenderKeyRequestMessage(closedGroupUpdate, from: publicKey, using: transaction) case .senderKey: handleSenderKeyMessage(closedGroupUpdate, from: publicKey, using: transaction) } } @@ -198,12 +205,12 @@ public final class ClosedGroupsProtocol : NSObject { let name = closedGroupUpdate.name let groupPrivateKey = closedGroupUpdate.groupPrivateKey! let senderKeys = closedGroupUpdate.senderKeys - let members = closedGroupUpdate.members - let admins = closedGroupUpdate.admins + let members = closedGroupUpdate.members.map { $0.toHexString() } + let admins = closedGroupUpdate.admins.map { $0.toHexString() } // Persist the ratchets senderKeys.forEach { senderKey in let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey, ratchet: ratchet, using: transaction) + Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) } // Create the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) @@ -230,18 +237,27 @@ public final class ClosedGroupsProtocol : NSObject { let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name let senderKeys = closedGroupUpdate.senderKeys - let members = closedGroupUpdate.members - let admins = closedGroupUpdate.admins + let members = closedGroupUpdate.members.map { $0.toHexString() } + let admins = closedGroupUpdate.admins.map { $0.toHexString() } // Get the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { return print("[Loki] Ignoring closed group update for nonexistent group.") } let group = thread.groupModel + // Check that the sender is a member of the group (before the update) + var membersAndLinkedDevices: Set = [] + for member in group.groupMemberIds { + let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) + membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.hexEncodedPublicKey, $0.slave.hexEncodedPublicKey ] }) + } + guard membersAndLinkedDevices.contains(senderPublicKey) else { + return print("[Loki] Ignoring closed group info message from non-member.") + } // Store the ratchets for any new members (it's important that this happens before the code below) senderKeys.forEach { senderKey in let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) - Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey, ratchet: ratchet, using: transaction) + Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) } // Delete all ratchets and either: // • Send out the user's new ratchet using established channels if other members of the group left or were removed @@ -256,7 +272,7 @@ public final class ClosedGroupsProtocol : NSObject { } else { establishSessionsIfNeeded(with: members, using: transaction) // This internally takes care of multi device let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) - let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: userPublicKey) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) for member in members { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) @@ -275,12 +291,62 @@ public final class ClosedGroupsProtocol : NSObject { infoMessage.save(with: transaction) } + private static func handleSenderKeyRequestMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + // Prepare + let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue + let userPublicKey = getUserHexEncodedPublicKey() + let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let groupThread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + return print("[Loki] Ignoring closed group update for nonexistent group.") + } + let group = groupThread.groupModel + // Check that the requesting user is a member of the group + var membersAndLinkedDevices: Set = [] + for member in group.groupMemberIds { + let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) + membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.hexEncodedPublicKey, $0.slave.hexEncodedPublicKey ] }) + } + guard membersAndLinkedDevices.contains(senderPublicKey) else { + return print("[Loki] Ignoring closed group sender key request from non-member.") + } + // Check that the current user is one of the members that the sender is requesting the sender key of + guard closedGroupUpdate.members.map({ $0.toHexString() }).contains(userPublicKey) else { + return print("[Loki] Ignoring closed group sender key request aimed at other members.") + } + // Respond to the request + SessionManagementProtocol.establishSessionIfNeeded(with: senderPublicKey, using: transaction) // This internally takes care of multi device + let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) + let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction) + thread.save(with: transaction) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey) + let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) + messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // This internally takes care of multi device + } + /// Invoked upon receiving a sender key from another user. private static func handleSenderKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + // Prepare let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) + guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else { + return print("[Loki] Ignoring closed group update for nonexistent group.") + } + let group = thread.groupModel guard let senderKey = closedGroupUpdate.senderKeys.first else { return print("[Loki] Ignoring invalid closed group update.") } + // Check that the requesting user is a member of the group + var membersAndLinkedDevices: Set = [] + for member in group.groupMemberIds { + let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) + membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.hexEncodedPublicKey, $0.slave.hexEncodedPublicKey ] }) + } + guard membersAndLinkedDevices.contains(senderPublicKey) else { + return print("[Loki] Ignoring closed group sender key from non-member.") + } + // Store the sender key let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, using: transaction) } diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/Storage+ClosedGroups.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/Storage+ClosedGroups.swift index 263f642d6..27ca746ea 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/Storage+ClosedGroups.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/Storage+ClosedGroups.swift @@ -26,7 +26,7 @@ public extension Storage { read { transaction in transaction.enumerateRows(inCollection: collection) { key, object, _, _ in guard let publicKey = key as? String, let ratchet = object as? ClosedGroupRatchet else { return } - let senderKey = ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: publicKey) + let senderKey = ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) result.insert(senderKey) } } diff --git a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift index cce1b4483..1cc8d25c1 100644 --- a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift @@ -74,8 +74,8 @@ public final class SyncMessagesProtocol : NSObject { let group = thread.groupModel let groupPublicKey = LKGroupUtilities.getDecodedGroupID(group.groupId) let name = group.groupName! - let members = group.groupMemberIds - let admins = group.groupAdminIds + let members = group.groupMemberIds.map { Data(hex: $0) } + let admins = group.groupAdminIds.map { Data(hex: $0) } guard let groupPrivateKey = Storage.getClosedGroupPrivateKey(for: groupPublicKey) else { print("[Loki] Couldn't get private key for SSK based closed group.") return AnyPromise.from(Promise(error: SyncMessagesProtocolError.privateKeyMissing)) @@ -87,7 +87,7 @@ public final class SyncMessagesProtocol : NSObject { let linkedDevices = deviceLinks.flatMap { [ $0.master.hexEncodedPublicKey, $0.slave.hexEncodedPublicKey ] }.filter { $0 != userPublicKey } let senderKeys: [ClosedGroupSenderKey] = linkedDevices.map { publicKey in let ratchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) - return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: publicKey) + return ClosedGroupSenderKey(chainKey: Data(hex: ratchet.chainKey), keyIndex: ratchet.keyIndex, publicKey: Data(hex: publicKey)) } // Send a closed group update message to the existing members with the linked devices' ratchets (this message is aimed at the group) func sendMessageToGroup() { diff --git a/SignalServiceKit/src/Protos/Generated/SSKProto.swift b/SignalServiceKit/src/Protos/Generated/SSKProto.swift index ce4ea9408..688e8ef74 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProto.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProto.swift @@ -3293,7 +3293,7 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { // MARK: - SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder - @objc public class func builder(chainKey: Data, keyIndex: UInt32, publicKey: String) -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { + @objc public class func builder(chainKey: Data, keyIndex: UInt32, publicKey: Data) -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { return SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder(chainKey: chainKey, keyIndex: keyIndex, publicKey: publicKey) } @@ -3309,7 +3309,7 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { @objc fileprivate override init() {} - @objc fileprivate init(chainKey: Data, keyIndex: UInt32, publicKey: String) { + @objc fileprivate init(chainKey: Data, keyIndex: UInt32, publicKey: Data) { super.init() setChainKey(chainKey) @@ -3325,7 +3325,7 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { proto.keyIndex = valueParam } - @objc public func setPublicKey(_ valueParam: String) { + @objc public func setPublicKey(_ valueParam: Data) { proto.publicKey = valueParam } @@ -3344,12 +3344,12 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { @objc public let keyIndex: UInt32 - @objc public let publicKey: String + @objc public let publicKey: Data private init(proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey, chainKey: Data, keyIndex: UInt32, - publicKey: String) { + publicKey: Data) { self.proto = proto self.chainKey = chainKey self.keyIndex = keyIndex @@ -3423,13 +3423,15 @@ extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClose @objc public enum SSKProtoDataMessageClosedGroupUpdateType: Int32 { case new = 0 case info = 1 - case senderKey = 2 + case senderKeyRequest = 2 + case senderKey = 3 } private class func SSKProtoDataMessageClosedGroupUpdateTypeWrap(_ value: SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum) -> SSKProtoDataMessageClosedGroupUpdateType { switch value { case .new: return .new case .info: return .info + case .senderKeyRequest: return .senderKeyRequest case .senderKey: return .senderKey } } @@ -3438,6 +3440,7 @@ extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClose switch value { case .new: return .new case .info: return .info + case .senderKeyRequest: return .senderKeyRequest case .senderKey: return .senderKey } } @@ -3498,23 +3501,23 @@ extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClose proto.senderKeys = wrappedItems.map { $0.proto } } - @objc public func addMembers(_ valueParam: String) { + @objc public func addMembers(_ valueParam: Data) { var items = proto.members items.append(valueParam) proto.members = items } - @objc public func setMembers(_ wrappedItems: [String]) { + @objc public func setMembers(_ wrappedItems: [Data]) { proto.members = wrappedItems } - @objc public func addAdmins(_ valueParam: String) { + @objc public func addAdmins(_ valueParam: Data) { var items = proto.admins items.append(valueParam) proto.admins = items } - @objc public func setAdmins(_ wrappedItems: [String]) { + @objc public func setAdmins(_ wrappedItems: [Data]) { proto.admins = wrappedItems } @@ -3559,11 +3562,11 @@ extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClose return proto.hasGroupPrivateKey } - @objc public var members: [String] { + @objc public var members: [Data] { return proto.members } - @objc public var admins: [String] { + @objc public var admins: [Data] { return proto.admins } diff --git a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift index adaac0663..1ce1b34a1 100644 --- a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift +++ b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift @@ -1527,9 +1527,9 @@ struct SignalServiceProtos_DataMessage { var senderKeys: [SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey] = [] - var members: [String] = [] + var members: [Data] = [] - var admins: [String] = [] + var admins: [Data] = [] /// @required var type: SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum { @@ -1552,8 +1552,11 @@ struct SignalServiceProtos_DataMessage { /// groupPublicKey, name, senderKeys, members, admins case info // = 1 + /// groupPublicKey + case senderKeyRequest // = 2 + /// groupPublicKey, senderKeys - case senderKey // = 2 + case senderKey // = 3 init() { self = .new @@ -1563,7 +1566,8 @@ struct SignalServiceProtos_DataMessage { switch rawValue { case 0: self = .new case 1: self = .info - case 2: self = .senderKey + case 2: self = .senderKeyRequest + case 3: self = .senderKey default: return nil } } @@ -1572,7 +1576,8 @@ struct SignalServiceProtos_DataMessage { switch self { case .new: return 0 case .info: return 1 - case .senderKey: return 2 + case .senderKeyRequest: return 2 + case .senderKey: return 3 } } @@ -1604,8 +1609,8 @@ struct SignalServiceProtos_DataMessage { mutating func clearKeyIndex() {self._keyIndex = nil} /// @required - var publicKey: String { - get {return _publicKey ?? String()} + var publicKey: Data { + get {return _publicKey ?? SwiftProtobuf.Internal.emptyData} set {_publicKey = newValue} } /// Returns true if `publicKey` has been explicitly set. @@ -1619,7 +1624,7 @@ struct SignalServiceProtos_DataMessage { fileprivate var _chainKey: Data? = nil fileprivate var _keyIndex: UInt32? = nil - fileprivate var _publicKey: String? = nil + fileprivate var _publicKey: Data? = nil } init() {} @@ -4044,8 +4049,8 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa case 2: try decoder.decodeSingularBytesField(value: &self._groupPublicKey) case 3: try decoder.decodeSingularBytesField(value: &self._groupPrivateKey) case 4: try decoder.decodeRepeatedMessageField(value: &self.senderKeys) - case 5: try decoder.decodeRepeatedStringField(value: &self.members) - case 6: try decoder.decodeRepeatedStringField(value: &self.admins) + case 5: try decoder.decodeRepeatedBytesField(value: &self.members) + case 6: try decoder.decodeRepeatedBytesField(value: &self.admins) case 7: try decoder.decodeSingularEnumField(value: &self._type) default: break } @@ -4066,10 +4071,10 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa try visitor.visitRepeatedMessageField(value: self.senderKeys, fieldNumber: 4) } if !self.members.isEmpty { - try visitor.visitRepeatedStringField(value: self.members, fieldNumber: 5) + try visitor.visitRepeatedBytesField(value: self.members, fieldNumber: 5) } if !self.admins.isEmpty { - try visitor.visitRepeatedStringField(value: self.admins, fieldNumber: 6) + try visitor.visitRepeatedBytesField(value: self.admins, fieldNumber: 6) } if let v = self._type { try visitor.visitSingularEnumField(value: v, fieldNumber: 7) @@ -4094,7 +4099,8 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum: SwiftProto static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 0: .same(proto: "NEW"), 1: .same(proto: "INFO"), - 2: .same(proto: "SENDER_KEY"), + 2: .same(proto: "SENDER_KEY_REQUEST"), + 3: .same(proto: "SENDER_KEY"), ] } @@ -4111,7 +4117,7 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey: SwiftProt switch fieldNumber { case 1: try decoder.decodeSingularBytesField(value: &self._chainKey) case 2: try decoder.decodeSingularUInt32Field(value: &self._keyIndex) - case 3: try decoder.decodeSingularStringField(value: &self._publicKey) + case 3: try decoder.decodeSingularBytesField(value: &self._publicKey) default: break } } @@ -4125,7 +4131,7 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey: SwiftProt try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) } if let v = self._publicKey { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) + try visitor.visitSingularBytesField(value: v, fieldNumber: 3) } try unknownFields.traverse(visitor: &visitor) }