Merge pull request #294 from loki-project/shared-sender-keys

Fix SSK Group Leaving Race Condition
pull/298/head
Niels Andriesse 5 years ago committed by GitHub
commit 43724d6578
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -241,13 +241,17 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega
guard members != Set(thread.groupModel.groupMemberIds) || name != thread.groupModel.groupName else { guard members != Set(thread.groupModel.groupMemberIds) || name != thread.groupModel.groupName else {
return popToConversationVC(self) return popToConversationVC(self)
} }
try! Storage.writeSync { [weak self] transaction in ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in
ClosedGroupsProtocol.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { try! Storage.writeSync { [weak self] transaction in
guard let self = self else { return } ClosedGroupsProtocol.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) {
popToConversationVC(self) guard let self = self else { return }
}.catch(on: DispatchQueue.main) { error in self.dismiss(animated: true, completion: nil) // Dismiss the loader
guard let self = self else { return } popToConversationVC(self)
self.showError(title: "Couldn't Update Group", message: "Please check your internet connection and try again.") }.catch(on: DispatchQueue.main) { error in
guard let self = self else { return }
self.dismiss(animated: true, completion: nil) // Dismiss the loader
self.showError(title: "Couldn't Update Group", message: "Please check your internet connection and try again.")
}
} }
} }
} }

@ -118,11 +118,18 @@ public final class ClosedGroupsProtocol : NSObject {
print("[Loki] Can't remove self and others simultaneously.") print("[Loki] Can't remove self and others simultaneously.")
return Promise(error: Error.invalidUpdate) return Promise(error: Error.invalidUpdate)
} }
// Send the update to the group (don't include new ratchets as everyone should regenerate new ratchets individually) // Establish sessions if needed
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [], establishSessionsIfNeeded(with: [String](members), using: transaction)
members: membersAsData, admins: adminsAsData) // Send the update to the existing members using established channels (don't include new ratchets as everyone should regenerate new ratchets individually)
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind) let promises: [Promise<Void>] = oldMembers.map { member in
SSKEnvironment.shared.messageSender.send(closedGroupUpdateMessage, success: { seal.fulfill(()) }, failure: { seal.reject($0) }) let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
thread.save(with: transaction)
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name, senderKeys: [],
members: membersAsData, admins: adminsAsData)
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
return SSKEnvironment.shared.messageSender.sendPromise(message: closedGroupUpdateMessage)
}
when(resolved: promises).done2 { _ in seal.fulfill(()) }.catch2 { seal.reject($0) }
promise.done { promise.done {
try! Storage.writeSync { transaction in try! Storage.writeSync { transaction in
// Delete all ratchets (it's important that this happens * after * sending out the update) // Delete all ratchets (it's important that this happens * after * sending out the update)
@ -134,8 +141,6 @@ public final class ClosedGroupsProtocol : NSObject {
// Notify the PN server // Notify the PN server
LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey) LokiPushNotificationManager.performOperation(.unsubscribe, for: groupPublicKey, publicKey: userPublicKey)
} else { } else {
// Establish sessions if needed
establishSessionsIfNeeded(with: [String](members), using: transaction)
// Send closed group update messages to any new members using established channels // Send closed group update messages to any new members using established channels
for member in newMembers { for member in newMembers {
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction) let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
@ -203,13 +208,13 @@ public final class ClosedGroupsProtocol : NSObject {
return promise return promise
} }
/// The returned promise is fulfilled when the message has been sent **to the group**. It doesn't wait for the user's new ratchet to be distributed. /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed.
@objc(leaveGroupWithPublicKey:transaction:) @objc(leaveGroupWithPublicKey:transaction:)
public static func objc_leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { public static func objc_leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise {
return AnyPromise.from(leave(groupPublicKey, using: transaction)) return AnyPromise.from(leave(groupPublicKey, using: transaction))
} }
/// The returned promise is fulfilled when the message has been sent **to the group**. It doesn't wait for the user's new ratchet to be distributed. /// The returned promise is fulfilled when the group update message has been sent. It doesn't wait for the user's new ratchet to be distributed.
public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise<Void> { public static func leave(_ groupPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise<Void> {
let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey() let userPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] ?? getUserHexEncodedPublicKey()
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)

Loading…
Cancel
Save