pull/218/head
nielsandriesse 5 years ago
parent 4cb1cb6b93
commit b01cb971e6

@ -118,12 +118,13 @@ public final class ClosedGroupsProtocol : NSObject {
}
public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
removeMembers([ getUserHexEncodedPublicKey() ], from: groupPublicKey, using: transaction)
let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey()
removeMembers([ userPublicKey ], from: groupPublicKey, using: transaction)
}
public static func removeMembers(_ membersToRemove: Set<String>, from groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
// Prepare
let userPublicKey = getUserHexEncodedPublicKey()
let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey()
let isUserLeaving = membersToRemove.contains(userPublicKey)
guard !isUserLeaving || membersToRemove.count == 1 else {
return print("[Loki] Can't remove self and others simultaneously.")
@ -158,6 +159,7 @@ public final class ClosedGroupsProtocol : NSObject {
// Establish sessions if needed
establishSessionsIfNeeded(with: members, using: transaction) // This internally takes care of multi device
// 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)
for member in members { // This internally takes care of multi device
@ -223,8 +225,9 @@ 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, from senderPublicKey: String,
using transaction: YapDatabaseReadWriteTransaction) {
using transaction: YapDatabaseReadWriteTransaction) {
// Unwrap the message
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString()
let name = closedGroupUpdate.name
let senderKeys = closedGroupUpdate.senderKeys
@ -244,27 +247,32 @@ public final class ClosedGroupsProtocol : NSObject {
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) // This internally takes care of multi device
// 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)
}
// Delete all ratchets and send out the user's new ratchet using established channels if any member of the group left or was removed
// 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
// Remove the group from the user's set of public keys to poll for if the current user was among the members that were removed
let oldMembers = group.groupMemberIds
let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey()
let wasUserRemoved = !members.contains(userPublicKey)
if Set(members).intersection(oldMembers) != Set(oldMembers) {
Storage.removeAllClosedGroupRatchets(for: groupPublicKey, using: transaction)
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)
for member in members {
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
thread.save(with: transaction)
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey)
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
if wasUserRemoved {
Storage.removeClosedGroupPrivateKey(for: groupPublicKey, using: transaction)
} 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)
for member in members {
let thread = TSContactThread.getOrCreateThread(withContactId: member, 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
}
}
}
// Update the group
@ -272,11 +280,12 @@ public final class ClosedGroupsProtocol : NSObject {
let newGroupModel = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupIDAsData, groupType: .closedGroup, adminIds: admins)
thread.setGroupModel(newGroupModel, with: transaction)
// Notify the user
let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeGroupUpdate)
let infoMessageType: TSInfoMessageType = wasUserRemoved ? .typeGroupQuit : .typeGroupUpdate
let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: infoMessageType)
infoMessage.save(with: transaction)
}
/// Invoked upon receiving a chain key from another user.
/// Invoked upon receiving a sender key from another user.
private static func handleSenderKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString()
guard let senderKey = closedGroupUpdate.senderKeys.first else {
@ -315,4 +324,3 @@ public final class ClosedGroupsProtocol : NSObject {
return result
}
}

Loading…
Cancel
Save