mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge pull request #223 from loki-project/shared-sender-keys
SSK Protocol Changes
This commit is contained in:
commit
e25f4aec38
12 changed files with 200 additions and 85 deletions
30
Podfile.lock
30
Podfile.lock
|
@ -42,13 +42,13 @@ PODS:
|
|||
- PureLayout (3.1.6)
|
||||
- Reachability (3.2)
|
||||
- SAMKeychain (1.5.3)
|
||||
- SessionAxolotlKit (1.0.5):
|
||||
- SessionAxolotlKit (1.0.6):
|
||||
- CocoaLumberjack
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.2)
|
||||
- SessionHKDFKit (~> 0.0.5)
|
||||
- SwiftProtobuf (~> 1.5.0)
|
||||
- SessionAxolotlKit/Tests (1.0.5):
|
||||
- SessionAxolotlKit/Tests (1.0.6):
|
||||
- CocoaLumberjack
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.2)
|
||||
|
@ -72,18 +72,18 @@ PODS:
|
|||
- SessionHKDFKit/Tests (0.0.5):
|
||||
- CocoaLumberjack
|
||||
- SessionCoreKit
|
||||
- SessionMetadataKit (1.0.5):
|
||||
- SessionMetadataKit (1.0.6):
|
||||
- CocoaLumberjack
|
||||
- CryptoSwift (~> 1.3)
|
||||
- SessionAxolotlKit (~> 1.0.5)
|
||||
- SessionAxolotlKit (~> 1.0.6)
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.2)
|
||||
- SessionHKDFKit (~> 0.0.5)
|
||||
- SwiftProtobuf (~> 1.5.0)
|
||||
- SessionMetadataKit/Tests (1.0.5):
|
||||
- SessionMetadataKit/Tests (1.0.6):
|
||||
- CocoaLumberjack
|
||||
- CryptoSwift (~> 1.3)
|
||||
- SessionAxolotlKit (~> 1.0.5)
|
||||
- SessionAxolotlKit (~> 1.0.6)
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.2)
|
||||
- SessionHKDFKit (~> 0.0.5)
|
||||
|
@ -98,10 +98,10 @@ PODS:
|
|||
- PromiseKit (~> 6.0)
|
||||
- Reachability
|
||||
- SAMKeychain
|
||||
- SessionAxolotlKit (~> 1.0.5)
|
||||
- SessionAxolotlKit (~> 1.0.6)
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.3)
|
||||
- SessionMetadataKit (~> 1.0.5)
|
||||
- SessionMetadataKit (~> 1.0.6)
|
||||
- Starscream
|
||||
- SwiftProtobuf (~> 1.5.0)
|
||||
- YapDatabase/SQLCipher
|
||||
|
@ -115,10 +115,10 @@ PODS:
|
|||
- PromiseKit (~> 6.0)
|
||||
- Reachability
|
||||
- SAMKeychain
|
||||
- SessionAxolotlKit (~> 1.0.5)
|
||||
- SessionAxolotlKit (~> 1.0.6)
|
||||
- SessionCoreKit (~> 1.0.0)
|
||||
- SessionCurve25519Kit (~> 2.1.3)
|
||||
- SessionMetadataKit (~> 1.0.5)
|
||||
- SessionMetadataKit (~> 1.0.6)
|
||||
- Starscream
|
||||
- SwiftProtobuf (~> 1.5.0)
|
||||
- YapDatabase/SQLCipher
|
||||
|
@ -277,7 +277,7 @@ CHECKOUT OPTIONS:
|
|||
:commit: b72c2d1e6132501db906de2cffa8ded7803c54f4
|
||||
:git: https://github.com/signalapp/Mantle
|
||||
SessionAxolotlKit:
|
||||
:commit: 27b63f4ecb890c38a78750e12d1569033074915b
|
||||
:commit: 663f58f4da7bf4d159e366352c2bb7715049671b
|
||||
:git: https://github.com/loki-project/session-ios-protocol-kit.git
|
||||
SessionCoreKit:
|
||||
:commit: 0d66c90657b62cb66ecd2767c57408a951650f23
|
||||
|
@ -289,7 +289,7 @@ CHECKOUT OPTIONS:
|
|||
:commit: 0dcf8cf8a7995ef8663146f7063e6c1d7f5a3274
|
||||
:git: https://github.com/nielsandriesse/session-ios-hkdf-kit.git
|
||||
SessionMetadataKit:
|
||||
:commit: bddba9ef2050af9a223f2698528776b6b80dc221
|
||||
:commit: 935300f1de6c3e6b77fd6f7ad69b7ce3d7ee9ab5
|
||||
:git: https://github.com/loki-project/session-ios-metadata-kit
|
||||
Starscream:
|
||||
:commit: b09ea163c3cb305152c65b299cb024610f52e735
|
||||
|
@ -312,12 +312,12 @@ SPEC CHECKSUMS:
|
|||
PureLayout: bd3c4ec3a3819ad387c99ebb72c6b129c3ed4d2d
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
SessionAxolotlKit: e6c39822a8ad68217966f02ce135291023938144
|
||||
SessionAxolotlKit: f65b7402b63549597e23bc6c8f92c5e2da182ae4
|
||||
SessionCoreKit: 778a3f6e3da788b43497734166646025b6392e88
|
||||
SessionCurve25519Kit: 9bb9afe199e4bc23578a4b15932ad2c57bd047b1
|
||||
SessionHKDFKit: b0f4e669411703ab925aba07491c5611564d1419
|
||||
SessionMetadataKit: f5d9cc78092f84f3940822506c14a381e79af9ff
|
||||
SessionServiceKit: 0a50bd8482a0787a6f7134b4c0854a0a091535e8
|
||||
SessionMetadataKit: 1e5dbd59f6229d9238557751bfbc57c0f4b1dd6b
|
||||
SessionServiceKit: 903f4a01384ad4f827e035e693cd87605c223724
|
||||
SQLCipher: e434ed542b24f38ea7b36468a13f9765e1b5c072
|
||||
SSZipArchive: 62d4947b08730e4cda640473b0066d209ff033c9
|
||||
Starscream: 8aaf1a7feb805c816d0e7d3190ef23856f6665b9
|
||||
|
|
2
Pods
2
Pods
|
@ -1 +1 @@
|
|||
Subproject commit 49611da3fc5eac88efd8d192e9ca7e2a84813a7e
|
||||
Subproject commit 158e066d79806ef0e466370da5c303dedb90c654
|
|
@ -42,7 +42,7 @@ A Swift/Objective-C library for communicating with the Session messaging service
|
|||
s.dependency 'CocoaLumberjack'
|
||||
s.dependency 'CryptoSwift', '~> 1.3'
|
||||
s.dependency 'AFNetworking'
|
||||
s.dependency 'SessionAxolotlKit', '~> 1.0.5'
|
||||
s.dependency 'SessionAxolotlKit', '~> 1.0.6'
|
||||
s.dependency 'Mantle'
|
||||
s.dependency 'YapDatabase/SQLCipher'
|
||||
s.dependency 'Starscream'
|
||||
|
@ -52,7 +52,7 @@ A Swift/Objective-C library for communicating with the Session messaging service
|
|||
s.dependency 'Reachability'
|
||||
s.dependency 'SwiftProtobuf', '~> 1.5.0'
|
||||
s.dependency 'SessionCoreKit', '~> 1.0.0'
|
||||
s.dependency 'SessionMetadataKit', '~> 1.0.5'
|
||||
s.dependency 'SessionMetadataKit', '~> 1.0.6'
|
||||
s.dependency 'PromiseKit', '~> 6.0'
|
||||
|
||||
s.test_spec 'Tests' do |test_spec|
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) ]"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey)
|
||||
}
|
||||
|
||||
|
@ -39,14 +40,17 @@ 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 else { return nil }
|
||||
self.kind = .senderKeyRequest(groupPublicKey: groupPublicKey)
|
||||
case "senderKey":
|
||||
guard let senderKey = senderKeys.first else { return nil }
|
||||
self.kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: senderKey)
|
||||
|
@ -76,6 +80,8 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage {
|
|||
coder.encode(senderKeys, forKey: "senderKeys")
|
||||
coder.encode(members, forKey: "members")
|
||||
coder.encode(admins, forKey: "admins")
|
||||
case .senderKeyRequest(let groupPublicKey):
|
||||
coder.encode(groupPublicKey, forKey: "groupPublicKey")
|
||||
case .senderKey(let groupPublicKey, let senderKey):
|
||||
coder.encode("senderKey", forKey: "kind")
|
||||
coder.encode(groupPublicKey, forKey: "groupPublicKey")
|
||||
|
@ -102,6 +108,8 @@ internal final class ClosedGroupUpdateMessage : TSOutgoingMessage {
|
|||
closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() })
|
||||
closedGroupUpdate.setMembers(members)
|
||||
closedGroupUpdate.setAdmins(admins)
|
||||
case .senderKeyRequest(let groupPublicKey):
|
||||
closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKeyRequest)
|
||||
case .senderKey(let groupPublicKey, let senderKey):
|
||||
closedGroupUpdate = SSKProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKey)
|
||||
closedGroupUpdate.setSenderKeys([ try senderKey.toProto() ])
|
||||
|
|
|
@ -14,6 +14,8 @@ import PromiseKit
|
|||
public final class ClosedGroupsProtocol : NSObject {
|
||||
public static let isSharedSenderKeysEnabled = false
|
||||
|
||||
// MARK: - Sending
|
||||
|
||||
/// - Note: It's recommended to batch fetch the device links for the given set of members before invoking this, to avoid the message sending pipeline
|
||||
/// making a request for each member.
|
||||
public static func createClosedGroup(name: String, members: Set<String>, transaction: YapDatabaseReadWriteTransaction) -> Promise<TSGroupThread> {
|
||||
|
@ -27,6 +29,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<String> = members
|
||||
for member in members {
|
||||
|
@ -35,10 +38,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 +57,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 +80,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<String> = newMembers
|
||||
for member in newMembers {
|
||||
|
@ -90,11 +96,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 +112,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 +144,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 +152,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 +170,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)
|
||||
|
@ -180,6 +188,20 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
infoMessage.save(with: transaction)
|
||||
}
|
||||
|
||||
public static func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
// Establish session if needed
|
||||
SessionManagementProtocol.establishSessionIfNeeded(with: senderPublicKey, using: transaction)
|
||||
// Send the request
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction)
|
||||
thread.save(with: transaction)
|
||||
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKeyRequest(groupPublicKey: Data(hex: groupPublicKey))
|
||||
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
||||
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
|
||||
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
||||
}
|
||||
|
||||
// MARK: - Receiving
|
||||
|
||||
@objc(handleSharedSenderKeysUpdateIfNeeded:from:transaction:)
|
||||
public static func handleSharedSenderKeysUpdateIfNeeded(_ dataMessage: SSKProtoDataMessage, from publicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
// Note that `publicKey` is either the public key of the group or the public key of the
|
||||
|
@ -188,6 +210,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 +221,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 +253,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<String> = []
|
||||
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 +288,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)
|
||||
|
@ -269,22 +301,72 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
// Update the group
|
||||
let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins)
|
||||
thread.setGroupModel(newGroupModel, with: transaction)
|
||||
// Notify the user
|
||||
let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate
|
||||
let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType)
|
||||
infoMessage.save(with: transaction)
|
||||
// Notify the user if needed (don't notify them if the message just contained linked device sender keys)
|
||||
if Set(members) != Set(oldMembers) || Set(admins) != Set(group.groupAdminIds) || name != group.groupName {
|
||||
let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate
|
||||
let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType)
|
||||
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<String> = []
|
||||
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.")
|
||||
}
|
||||
// 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<String> = []
|
||||
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)
|
||||
}
|
||||
|
||||
// MARK: - General
|
||||
|
||||
@objc(establishSessionsIfNeededWithClosedGroupMembers:transaction:)
|
||||
public static func establishSessionsIfNeeded(with closedGroupMembers: [String], using transaction: YapDatabaseReadWriteTransaction) {
|
||||
closedGroupMembers.forEach { publicKey in
|
||||
|
|
|
@ -149,11 +149,23 @@ public final class SharedSenderKeysImplementation : NSObject, SharedSenderKeysPr
|
|||
}
|
||||
|
||||
public func decrypt(_ ivAndCiphertext: Data, for groupPublicKey: String, senderPublicKey: String, keyIndex: UInt, using transaction: YapDatabaseReadWriteTransaction) throws -> Data {
|
||||
let ratchet = try stepRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, until: keyIndex, using: transaction)
|
||||
let ratchet: ClosedGroupRatchet
|
||||
do {
|
||||
ratchet = try stepRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, until: keyIndex, using: transaction)
|
||||
} catch {
|
||||
// FIXME: It'd be cleaner to handle this in OWSMessageDecrypter (where all the other decryption errors are handled), but this was a lot more
|
||||
// convenient because there's an easy way to get the sender public key from here.
|
||||
if case RatchetingError.loadingFailed(_, _) = error {
|
||||
ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
let iv = ivAndCiphertext[0..<Int(SharedSenderKeysImplementation.ivSize)]
|
||||
let ciphertext = ivAndCiphertext[Int(SharedSenderKeysImplementation.ivSize)...]
|
||||
let gcm = GCM(iv: iv.bytes, tagLength: Int(SharedSenderKeysImplementation.gcmTagSize), mode: .combined)
|
||||
guard let messageKey = ratchet.messageKeys.last else { throw RatchetingError.messageKeyMissing(targetKeyIndex: keyIndex, groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey) }
|
||||
guard let messageKey = ratchet.messageKeys.last else {
|
||||
throw RatchetingError.messageKeyMissing(targetKeyIndex: keyIndex, groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey)
|
||||
}
|
||||
let aes = try AES(key: Data(hex: messageKey).bytes, blockMode: gcm, padding: .noPadding)
|
||||
return Data(try aes.decrypt(ciphertext.bytes))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Void>(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() {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue