From c5a535685a5ba4856fed86eaf21fb2440cf639e1 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 3 Jul 2020 16:22:58 +1000 Subject: [PATCH] Partially resolve TODOs --- SignalServiceKit/protobuf/SignalService.proto | 9 +- .../ClosedGroupUpdateMessage.swift | 28 ++-- .../Closed Groups/ClosedGroupsProtocol.swift | 59 ++++---- .../src/Protos/Generated/SSKProto.swift | 138 ++++++++++++++++-- .../Protos/Generated/SignalService.pb.swift | 80 +++++++++- 5 files changed, 262 insertions(+), 52 deletions(-) diff --git a/SignalServiceKit/protobuf/SignalService.proto b/SignalServiceKit/protobuf/SignalService.proto index 0e3172d2b..3676e152a 100644 --- a/SignalServiceKit/protobuf/SignalService.proto +++ b/SignalServiceKit/protobuf/SignalService.proto @@ -248,11 +248,18 @@ message DataMessage { CHAIN_KEY = 2; // groupPublicKey, chainKeys } + message SenderKey { + // @required + optional bytes chainKey = 1; + // @required + optional uint32 keyIndex = 2; + } + optional string name = 1; // @required optional bytes groupPublicKey = 2; optional bytes groupPrivateKey = 3; - repeated bytes chainKeys = 4; + repeated SenderKey senderKeys = 4; repeated string members = 5; repeated string admins = 6; // @required diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift index a4e6547d2..bc74baa52 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupUpdateMessage.swift @@ -9,11 +9,21 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { @objc internal override func shouldBeSaved() -> Bool { return false } @objc internal override func shouldSyncTranscript() -> Bool { return false } + // MARK: Sender Key + internal struct SenderKey { + internal let chainKey: Data + internal let keyIndex: UInt + + internal func toProto() throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { + return try SSKProtoDataMessageClosedGroupUpdateSenderKey.builder(chainKey: chainKey, keyIndex: UInt32(keyIndex)).build() + } + } + // MARK: Kind internal enum Kind { - case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, chainKeys: [Data], members: [String], admins: [String]) - case info(groupPublicKey: Data, name: String, chainKeys: [Data], members: [String], admins: [String]) - case chainKey(groupPublicKey: Data, chainKey: Data) + case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [SenderKey], members: [String], admins: [String]) + case info(groupPublicKey: Data, name: String, senderKeys: [SenderKey], members: [String], admins: [String]) + case chainKey(groupPublicKey: Data, senderKey: SenderKey) } // MARK: Initialization @@ -38,22 +48,22 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage { do { let closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate.SSKProtoDataMessageClosedGroupUpdateBuilder switch kind { - case .new(let groupPublicKey, let name, let groupPrivateKey, let chainKeys, let members, let admins): + case .new(let groupPublicKey, let name, let groupPrivateKey, let senderKeys, let members, let admins): closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .new) closedGroupUpdate.setName(name) closedGroupUpdate.setGroupPrivateKey(groupPrivateKey) - closedGroupUpdate.setChainKeys(chainKeys) + closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() }) closedGroupUpdate.setMembers(members) closedGroupUpdate.setAdmins(admins) - case .info(let groupPublicKey, let name, let chainKeys, let members, let admins): + case .info(let groupPublicKey, let name, let senderKeys, let members, let admins): closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .info) closedGroupUpdate.setName(name) - closedGroupUpdate.setChainKeys(chainKeys) + closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() }) closedGroupUpdate.setMembers(members) closedGroupUpdate.setAdmins(admins) - case .chainKey(let groupPublicKey, let chainKey): + case .chainKey(let groupPublicKey, let senderKey): closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .chainKey) - closedGroupUpdate.setChainKeys([ chainKey ]) + closedGroupUpdate.setSenderKeys([ try senderKey.toProto() ]) } builder.setClosedGroupUpdate(try closedGroupUpdate.build()) } catch { diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index f37b901d0..4f475ff8c 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -15,9 +15,8 @@ public final class ClosedGroupsProtocol : NSObject { // TODO: // • Always reset all ratchets if someone leaves or is kicked? - // • Validate that update messages come from admins // • Closed group update message deserialization - // • Include key indexes + // • Group model saving // • Multi device // • ClosedGroupsProtocol // • SyncMessagesProtocol @@ -50,11 +49,11 @@ public final class ClosedGroupsProtocol : NSObject { // the user can only pick from existing contacts) establishSessionsIfNeeded(with: members, using: transaction) // Send a closed group update message to all members involved using established channels - let chainKeys = ratchets.map { Data(hex: $0.chainKey) } + let senderKeys = ratchets.map { ClosedGroupUpdateMessage.SenderKey(chainKey: Data(hex: $0.chainKey), keyIndex: $0.keyIndex) } for member in members { 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, chainKeys: chainKeys, members: members, admins: admins) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name, groupPrivateKey: groupKeyPair.privateKey, senderKeys: senderKeys, members: members, admins: admins) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) @@ -91,14 +90,16 @@ public final class ClosedGroupsProtocol : NSObject { } // Send a closed group update message to the existing members with the new members' ratchets (this message is // aimed at the group) - let chainKeys = ratchets.map { Data(hex: $0.chainKey) } - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, chainKeys: chainKeys, members: members, admins: admins) + let senderKeys = ratchets.map { ClosedGroupUpdateMessage.SenderKey(chainKey: Data(hex: $0.chainKey), keyIndex: $0.keyIndex) } + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: senderKeys, members: members, admins: admins) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // Send closed group update messages to the new members using established channels - let allChainKeys = Storage.getAllClosedGroupRatchets(for: groupPublicKey).map { Data(hex: $0.chainKey) } // TODO: We need to include the key index here as well + let allSenderKeys = Storage.getAllClosedGroupRatchets(for: groupPublicKey).map { + ClosedGroupUpdateMessage.SenderKey(chainKey: Data(hex: $0.chainKey), keyIndex: $0.keyIndex) + } for member in newMembers { - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, chainKeys: allChainKeys, members: members, admins: admins) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: allSenderKeys, members: members, admins: admins) let thread = TSContactThread.getOrCreateThread(contactId: member) thread.save(with: transaction) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) @@ -130,7 +131,7 @@ public final class ClosedGroupsProtocol : NSObject { // sessions would've already been established previously) establishSessionsIfNeeded(with: group.groupMemberIds, using: transaction) // Intentionally not `members` // Send a closed group update message to the removed members (this message is aimed at the group) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, chainKeys: [], members: members, admins: admins) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], members: members, admins: admins) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) // Generate new ratchets for everyone except the members that were removed (it's important that @@ -140,11 +141,11 @@ public final class ClosedGroupsProtocol : NSObject { } // Send a closed group update message to all members (minus the ones that were removed) with everyone's new // ratchets using established channels - let chainKeys = ratchets.map { Data(hex: $0.chainKey) } + let senderKeys = ratchets.map { ClosedGroupUpdateMessage.SenderKey(chainKey: Data(hex: $0.chainKey), keyIndex: $0.keyIndex) } for member in members { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, chainKeys: chainKeys, members: members, admins: admins) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: senderKeys, members: members, admins: admins) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) } @@ -170,7 +171,7 @@ public final class ClosedGroupsProtocol : NSObject { members.remove(at: indexOfUser) // Send the update to the group (don't include new ratchets as everyone should generate new ratchets // individually in this case) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, chainKeys: [], members: members, admins: admins) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], members: members, admins: admins) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) @@ -187,7 +188,7 @@ public final class ClosedGroupsProtocol : NSObject { guard let closedGroupUpdate = dataMessage.closedGroupUpdate else { return } switch closedGroupUpdate.type { case .new: handleNewGroupMessage(closedGroupUpdate, using: transaction) - case .info: handleInfoMessage(closedGroupUpdate, using: transaction) + case .info: handleInfoMessage(closedGroupUpdate, from: publicKey, using: transaction) case .chainKey: handleChainKeyMessage(closedGroupUpdate, from: publicKey, using: transaction) } } @@ -197,12 +198,12 @@ public final class ClosedGroupsProtocol : NSObject { let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name let groupPrivateKey = closedGroupUpdate.groupPrivateKey! - let chainKeys = closedGroupUpdate.chainKeys + let senderKeys = closedGroupUpdate.senderKeys let members = closedGroupUpdate.members let admins = closedGroupUpdate.admins // Persist the ratchets - zip(members, chainKeys).forEach { (member, chainKey) in - let ratchet = ClosedGroupRatchet(chainKey: chainKey.toHexString(), keyIndex: 0, messageKeys: []) + zip(members, senderKeys).forEach { (member, senderKey) in + let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: member, ratchet: ratchet, using: transaction) } // Create the group @@ -223,12 +224,11 @@ public final class ClosedGroupsProtocol : NSObject { /// Invoked upon receiving a group update. A group update is sent out when a group's name is changed, when new users /// are added, when users leave or are kicked, or if the group admins are changed. - private static func handleInfoMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { - // TODO: Check that the sender was an admin + private static func handleInfoMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { // Unwrap the message let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name - let chainKeys = closedGroupUpdate.chainKeys + let senderKeys = closedGroupUpdate.senderKeys let members = closedGroupUpdate.members let admins = closedGroupUpdate.admins // Get the group @@ -237,15 +237,23 @@ public final class ClosedGroupsProtocol : NSObject { return print("[Loki] Ignoring closed group update for nonexistent group.") } let group = thread.groupModel + // Check that the sender is an admin (before the update) + var isSenderAdmin = false + Storage.read { transaction in + isSenderAdmin = !thread.isUserAdmin(inGroup: senderPublicKey, transaction: transaction) // TODO: Validate that `senderPublicKey` here isn't the group public key + } + guard isSenderAdmin else { + return print("[Loki] Ignoring closed group update from non-admin.") + } // Establish sessions if needed (it's important that this happens before the code below) establishSessionsIfNeeded(with: members, using: transaction) // Parse out any new members and store their ratchets (it's important that // this happens before handling removed members) let oldMembers = group.groupMemberIds let newMembers = members.filter { !oldMembers.contains($0) } - if newMembers.count == chainKeys.count { // If someone left or was kicked the message won't have any chain keys - zip(newMembers, chainKeys).forEach { (member, chainKey) in - let ratchet = ClosedGroupRatchet(chainKey: chainKey.toHexString(), keyIndex: 0, messageKeys: []) + if newMembers.count == senderKeys.count { // If someone left or was kicked the message won't have any sender keys + zip(newMembers, senderKeys).forEach { (member, senderKey) in + let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: member, ratchet: ratchet, using: transaction) } } @@ -255,11 +263,12 @@ public final class ClosedGroupsProtocol : NSObject { Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction) let userPublicKey = getUserHexEncodedPublicKey() let newRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) + let newSenderKey = ClosedGroupUpdateMessage.SenderKey(chainKey: Data(hex: newRatchet.chainKey), keyIndex: newRatchet.keyIndex) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, ratchet: newRatchet, using: transaction) for member in members { let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) thread.save(with: transaction) - let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.chainKey(groupPublicKey: Data(hex: groupPublicKey), chainKey: Data(hex: newRatchet.chainKey)) + let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.chainKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: newSenderKey) let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction) @@ -277,10 +286,10 @@ public final class ClosedGroupsProtocol : NSObject { /// Invoked upon receiving a chain key from another user. private static func handleChainKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) { let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() - guard let chainKey = closedGroupUpdate.chainKeys.first else { + guard let senderKey = closedGroupUpdate.senderKeys.first else { return print("[Loki] Ignoring invalid closed group update.") } - let ratchet = ClosedGroupRatchet(chainKey: chainKey.toHexString(), keyIndex: 0, messageKeys: []) + 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/Protos/Generated/SSKProto.swift b/SignalServiceKit/src/Protos/Generated/SSKProto.swift index 915d96c8c..7ba70cb45 100644 --- a/SignalServiceKit/src/Protos/Generated/SSKProto.swift +++ b/SignalServiceKit/src/Protos/Generated/SSKProto.swift @@ -3287,6 +3287,118 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { #endif +// MARK: - SSKProtoDataMessageClosedGroupUpdateSenderKey + +@objc public class SSKProtoDataMessageClosedGroupUpdateSenderKey: NSObject { + + // MARK: - SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder + + @objc public class func builder(chainKey: Data, keyIndex: UInt32) -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { + return SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder(chainKey: chainKey, keyIndex: keyIndex) + } + + // asBuilder() constructs a builder that reflects the proto's contents. + @objc public func asBuilder() -> SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { + let builder = SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder(chainKey: chainKey, keyIndex: keyIndex) + return builder + } + + @objc public class SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder: NSObject { + + private var proto = SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey() + + @objc fileprivate override init() {} + + @objc fileprivate init(chainKey: Data, keyIndex: UInt32) { + super.init() + + setChainKey(chainKey) + setKeyIndex(keyIndex) + } + + @objc public func setChainKey(_ valueParam: Data) { + proto.chainKey = valueParam + } + + @objc public func setKeyIndex(_ valueParam: UInt32) { + proto.keyIndex = valueParam + } + + @objc public func build() throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { + return try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto(proto) + } + + @objc public func buildSerializedData() throws -> Data { + return try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto(proto).serializedData() + } + } + + fileprivate let proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey + + @objc public let chainKey: Data + + @objc public let keyIndex: UInt32 + + private init(proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey, + chainKey: Data, + keyIndex: UInt32) { + self.proto = proto + self.chainKey = chainKey + self.keyIndex = keyIndex + } + + @objc + public func serializedData() throws -> Data { + return try self.proto.serializedData() + } + + @objc public class func parseData(_ serializedData: Data) throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { + let proto = try SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey(serializedData: serializedData) + return try parseProto(proto) + } + + fileprivate class func parseProto(_ proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey) throws -> SSKProtoDataMessageClosedGroupUpdateSenderKey { + guard proto.hasChainKey else { + throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: chainKey") + } + let chainKey = proto.chainKey + + guard proto.hasKeyIndex else { + throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: keyIndex") + } + let keyIndex = proto.keyIndex + + // MARK: - Begin Validation Logic for SSKProtoDataMessageClosedGroupUpdateSenderKey - + + // MARK: - End Validation Logic for SSKProtoDataMessageClosedGroupUpdateSenderKey - + + let result = SSKProtoDataMessageClosedGroupUpdateSenderKey(proto: proto, + chainKey: chainKey, + keyIndex: keyIndex) + return result + } + + @objc public override var debugDescription: String { + return "\(proto)" + } +} + +#if DEBUG + +extension SSKProtoDataMessageClosedGroupUpdateSenderKey { + @objc public func serializedDataIgnoringErrors() -> Data? { + return try! self.serializedData() + } +} + +extension SSKProtoDataMessageClosedGroupUpdateSenderKey.SSKProtoDataMessageClosedGroupUpdateSenderKeyBuilder { + @objc public func buildIgnoringErrors() -> SSKProtoDataMessageClosedGroupUpdateSenderKey? { + return try! self.build() + } +} + +#endif + // MARK: - SSKProtoDataMessageClosedGroupUpdate @objc public class SSKProtoDataMessageClosedGroupUpdate: NSObject { @@ -3330,7 +3442,7 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { if let _value = groupPrivateKey { builder.setGroupPrivateKey(_value) } - builder.setChainKeys(chainKeys) + builder.setSenderKeys(senderKeys) builder.setMembers(members) builder.setAdmins(admins) return builder @@ -3361,14 +3473,14 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { proto.groupPrivateKey = valueParam } - @objc public func addChainKeys(_ valueParam: Data) { - var items = proto.chainKeys - items.append(valueParam) - proto.chainKeys = items + @objc public func addSenderKeys(_ valueParam: SSKProtoDataMessageClosedGroupUpdateSenderKey) { + var items = proto.senderKeys + items.append(valueParam.proto) + proto.senderKeys = items } - @objc public func setChainKeys(_ wrappedItems: [Data]) { - proto.chainKeys = wrappedItems + @objc public func setSenderKeys(_ wrappedItems: [SSKProtoDataMessageClosedGroupUpdateSenderKey]) { + proto.senderKeys = wrappedItems.map { $0.proto } } @objc public func addMembers(_ valueParam: String) { @@ -3408,6 +3520,8 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { @objc public let groupPublicKey: Data + @objc public let senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey] + @objc public let type: SSKProtoDataMessageClosedGroupUpdateType @objc public var name: String? { @@ -3430,10 +3544,6 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { return proto.hasGroupPrivateKey } - @objc public var chainKeys: [Data] { - return proto.chainKeys - } - @objc public var members: [String] { return proto.members } @@ -3444,9 +3554,11 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { private init(proto: SignalServiceProtos_DataMessage.ClosedGroupUpdate, groupPublicKey: Data, + senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey], type: SSKProtoDataMessageClosedGroupUpdateType) { self.proto = proto self.groupPublicKey = groupPublicKey + self.senderKeys = senderKeys self.type = type } @@ -3466,6 +3578,9 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { } let groupPublicKey = proto.groupPublicKey + var senderKeys: [SSKProtoDataMessageClosedGroupUpdateSenderKey] = [] + senderKeys = try proto.senderKeys.map { try SSKProtoDataMessageClosedGroupUpdateSenderKey.parseProto($0) } + guard proto.hasType else { throw SSKProtoError.invalidProtobuf(description: "\(logTag) missing required field: type") } @@ -3477,6 +3592,7 @@ extension SSKProtoDataMessageLokiProfile.SSKProtoDataMessageLokiProfileBuilder { let result = SSKProtoDataMessageClosedGroupUpdate(proto: proto, groupPublicKey: groupPublicKey, + senderKeys: senderKeys, type: type) return result } diff --git a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift index f1d917e6a..89ef5776a 100644 --- a/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift +++ b/SignalServiceKit/src/Protos/Generated/SignalService.pb.swift @@ -1525,7 +1525,7 @@ struct SignalServiceProtos_DataMessage { /// Clears the value of `groupPrivateKey`. Subsequent reads from it will return its default value. mutating func clearGroupPrivateKey() {self._groupPrivateKey = nil} - var chainKeys: [Data] = [] + var senderKeys: [SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey] = [] var members: [String] = [] @@ -1578,6 +1578,39 @@ struct SignalServiceProtos_DataMessage { } + struct SenderKey { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// @required + var chainKey: Data { + get {return _chainKey ?? SwiftProtobuf.Internal.emptyData} + set {_chainKey = newValue} + } + /// Returns true if `chainKey` has been explicitly set. + var hasChainKey: Bool {return self._chainKey != nil} + /// Clears the value of `chainKey`. Subsequent reads from it will return its default value. + mutating func clearChainKey() {self._chainKey = nil} + + /// @required + var keyIndex: UInt32 { + get {return _keyIndex ?? 0} + set {_keyIndex = newValue} + } + /// Returns true if `keyIndex` has been explicitly set. + var hasKeyIndex: Bool {return self._keyIndex != nil} + /// Clears the value of `keyIndex`. Subsequent reads from it will return its default value. + mutating func clearKeyIndex() {self._keyIndex = nil} + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _chainKey: Data? = nil + fileprivate var _keyIndex: UInt32? = nil + } + init() {} fileprivate var _name: String? = nil @@ -3987,7 +4020,7 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa 1: .same(proto: "name"), 2: .same(proto: "groupPublicKey"), 3: .same(proto: "groupPrivateKey"), - 4: .same(proto: "chainKeys"), + 4: .same(proto: "senderKeys"), 5: .same(proto: "members"), 6: .same(proto: "admins"), 7: .same(proto: "type"), @@ -3999,7 +4032,7 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa case 1: try decoder.decodeSingularStringField(value: &self._name) case 2: try decoder.decodeSingularBytesField(value: &self._groupPublicKey) case 3: try decoder.decodeSingularBytesField(value: &self._groupPrivateKey) - case 4: try decoder.decodeRepeatedBytesField(value: &self.chainKeys) + 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 7: try decoder.decodeSingularEnumField(value: &self._type) @@ -4018,8 +4051,8 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa if let v = self._groupPrivateKey { try visitor.visitSingularBytesField(value: v, fieldNumber: 3) } - if !self.chainKeys.isEmpty { - try visitor.visitRepeatedBytesField(value: self.chainKeys, fieldNumber: 4) + if !self.senderKeys.isEmpty { + try visitor.visitRepeatedMessageField(value: self.senderKeys, fieldNumber: 4) } if !self.members.isEmpty { try visitor.visitRepeatedStringField(value: self.members, fieldNumber: 5) @@ -4037,7 +4070,7 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate: SwiftProtobuf.Messa if lhs._name != rhs._name {return false} if lhs._groupPublicKey != rhs._groupPublicKey {return false} if lhs._groupPrivateKey != rhs._groupPrivateKey {return false} - if lhs.chainKeys != rhs.chainKeys {return false} + if lhs.senderKeys != rhs.senderKeys {return false} if lhs.members != rhs.members {return false} if lhs.admins != rhs.admins {return false} if lhs._type != rhs._type {return false} @@ -4054,6 +4087,41 @@ extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.TypeEnum: SwiftProto ] } +extension SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = SignalServiceProtos_DataMessage.ClosedGroupUpdate.protoMessageName + ".SenderKey" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "chainKey"), + 2: .same(proto: "keyIndex"), + ] + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + switch fieldNumber { + case 1: try decoder.decodeSingularBytesField(value: &self._chainKey) + case 2: try decoder.decodeSingularUInt32Field(value: &self._keyIndex) + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if let v = self._chainKey { + try visitor.visitSingularBytesField(value: v, fieldNumber: 1) + } + if let v = self._keyIndex { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey, rhs: SignalServiceProtos_DataMessage.ClosedGroupUpdate.SenderKey) -> Bool { + if lhs._chainKey != rhs._chainKey {return false} + if lhs._keyIndex != rhs._keyIndex {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension SignalServiceProtos_NullMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".NullMessage" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [