From 3d9720c844a1c2944de57e17a527a58e208c2d16 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Fri, 25 Sep 2020 16:38:45 +1000 Subject: [PATCH 1/6] fix the issue that iOS didn't handle ssk group leaving issue --- .../src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index 581fbd914..aa5627070 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -301,7 +301,7 @@ public final class ClosedGroupsProtocol : NSObject { } let group = thread.groupModel // Check that the sender is a member of the group (before the update) - var membersAndLinkedDevices: Set = Set(members) + var membersAndLinkedDevices: Set = Set(group.groupMemberIds) for member in group.groupMemberIds { let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction) membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] }) From b0e38c0e7255d1b66703799223405ea100d5e3fc Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 25 Sep 2020 16:44:12 +1000 Subject: [PATCH 2/6] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 75c4dedf1..88d92ce84 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4123,7 +4123,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4185,7 +4185,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4239,7 +4239,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4309,7 +4309,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4371,7 +4371,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4434,7 +4434,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4635,7 +4635,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4702,7 +4702,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 25ff4482b64831cf25ebbaf923210ef81e34c640 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 28 Sep 2020 09:18:11 +1000 Subject: [PATCH 3/6] Don't acknowledge messages to the PN server --- SignalServiceKit/src/Loki/API/SnodeAPI.swift | 9 ++------- .../LokiPushNotificationManager.swift | 17 ----------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/SnodeAPI.swift b/SignalServiceKit/src/Loki/API/SnodeAPI.swift index d61d810d8..ec240ec46 100644 --- a/SignalServiceKit/src/Loki/API/SnodeAPI.swift +++ b/SignalServiceKit/src/Loki/API/SnodeAPI.swift @@ -243,25 +243,20 @@ public final class SnodeAPI : NSObject { internal static func parseRawMessagesResponse(_ rawResponse: Any, from snode: Snode, associatedWith publicKey: String) -> [SSKProtoEnvelope] { guard let json = rawResponse as? JSON, let rawMessages = json["messages"] as? [JSON] else { return [] } - if let (lastHash, expirationDate) = updateLastMessageHashValueIfPossible(for: snode, associatedWith: publicKey, from: rawMessages), - UserDefaults.standard[.isUsingFullAPNs] { - LokiPushNotificationManager.acknowledgeDelivery(forMessageWithHash: lastHash, expiration: expirationDate, publicKey: getUserHexEncodedPublicKey()) - } + updateLastMessageHashValueIfPossible(for: snode, associatedWith: publicKey, from: rawMessages) let rawNewMessages = removeDuplicates(from: rawMessages, associatedWith: publicKey) let newMessages = parseProtoEnvelopes(from: rawNewMessages) return newMessages } - private static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from rawMessages: [JSON]) -> (String, UInt64)? { + private static func updateLastMessageHashValueIfPossible(for snode: Snode, associatedWith publicKey: String, from rawMessages: [JSON]) { if let lastMessage = rawMessages.last, let lastHash = lastMessage["hash"] as? String, let expirationDate = lastMessage["expiration"] as? UInt64 { try! Storage.writeSync { transaction in Storage.setLastMessageHashInfo(for: snode, associatedWith: publicKey, to: [ "hash" : lastHash, "expirationDate" : NSNumber(value: expirationDate) ], using: transaction) } - return (lastHash, expirationDate) } else if (!rawMessages.isEmpty) { print("[Loki] Failed to update last message hash value from: \(rawMessages).") } - return nil } private static func removeDuplicates(from rawMessages: [JSON], associatedWith publicKey: String) -> [JSON] { diff --git a/SignalServiceKit/src/Loki/Push Notifications/LokiPushNotificationManager.swift b/SignalServiceKit/src/Loki/Push Notifications/LokiPushNotificationManager.swift index 21a01c20a..0ea0ffe94 100644 --- a/SignalServiceKit/src/Loki/Push Notifications/LokiPushNotificationManager.swift +++ b/SignalServiceKit/src/Loki/Push Notifications/LokiPushNotificationManager.swift @@ -143,21 +143,4 @@ public final class LokiPushNotificationManager : NSObject { static func objc_notify(for signalMessage: SignalMessage) -> AnyPromise { return AnyPromise.from(notify(for: signalMessage)) } - - static func acknowledgeDelivery(forMessageWithHash hash: String, expiration: UInt64, publicKey: String) { - let parameters: JSON = [ "lastHash" : hash, "pubKey" : publicKey, "expiration" : expiration] - let url = URL(string: "\(server)/acknowledge_message_delivery")! - let request = TSRequest(url: url, method: "POST", parameters: parameters) - request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ] - TSNetworkManager.shared().makeRequest(request, success: { _, response in - guard let json = response as? JSON else { - return print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash).") - } - guard json["code"] as? Int != 0 else { - return print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash) due to error: \(json["message"] as? String ?? "nil").") - } - }, failure: { _, error in - print("[Loki] Couldn't acknowledge delivery for message with hash: \(hash) due to error: \(error).") - }) - } } From e9b4a100a12f3088ac6d4e86ab9fd1dfde08053d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 28 Sep 2020 09:31:34 +1000 Subject: [PATCH 4/6] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 88d92ce84..4d8debfb3 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4123,7 +4123,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4185,7 +4185,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4239,7 +4239,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4309,7 +4309,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4371,7 +4371,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4434,7 +4434,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4635,7 +4635,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4702,7 +4702,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 5996bd949614f17384c909e1e4953ee03115cf33 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 28 Sep 2020 18:29:02 +1000 Subject: [PATCH 5/6] Don't keep old message keys around --- .../Protocol/Closed Groups/SharedSenderKeysImplementation.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/SharedSenderKeysImplementation.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/SharedSenderKeysImplementation.swift index b382b0bd7..170158c6f 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/SharedSenderKeysImplementation.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/SharedSenderKeysImplementation.swift @@ -66,7 +66,7 @@ public final class SharedSenderKeysImplementation : NSObject { let nextMessageKey = try HMAC(key: Data(hex: ratchet.chainKey).bytes, variant: .sha256).authenticate([ UInt8(1) ]) let nextChainKey = try HMAC(key: Data(hex: ratchet.chainKey).bytes, variant: .sha256).authenticate([ UInt8(2) ]) let nextKeyIndex = ratchet.keyIndex + 1 - return ClosedGroupRatchet(chainKey: nextChainKey.toHexString(), keyIndex: nextKeyIndex, messageKeys: ratchet.messageKeys + [ nextMessageKey.toHexString() ]) + return ClosedGroupRatchet(chainKey: nextChainKey.toHexString(), keyIndex: nextKeyIndex, messageKeys: [ nextMessageKey.toHexString() ]) } /// - Note: Sync. Don't call from the main thread. From 7a22b981f2b769384c1ed1d81725beb718a42f08 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 29 Sep 2020 13:41:42 +1000 Subject: [PATCH 6/6] Fix adding and removing members simultaneously --- .../Closed Groups/ClosedGroupsProtocol.swift | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index aa5627070..d48d729f7 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -243,8 +243,8 @@ public final class ClosedGroupsProtocol : NSObject { private static func isValid(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate) -> Bool { guard !closedGroupUpdate.groupPublicKey.isEmpty else { return false } switch closedGroupUpdate.type { - case .new: return !(closedGroupUpdate.name ?? "").isEmpty && !(closedGroupUpdate.groupPrivateKey ?? Data()).isEmpty && !closedGroupUpdate.senderKeys.isEmpty - && !closedGroupUpdate.members.isEmpty && !closedGroupUpdate.admins.isEmpty + case .new: return !(closedGroupUpdate.name ?? "").isEmpty && !(closedGroupUpdate.groupPrivateKey ?? Data()).isEmpty && !closedGroupUpdate.members.isEmpty + && !closedGroupUpdate.admins.isEmpty // senderKeys may be empty case .info: return !(closedGroupUpdate.name ?? "").isEmpty && !closedGroupUpdate.members.isEmpty && !closedGroupUpdate.admins.isEmpty // senderKeys may be empty case .senderKeyRequest: return true case .senderKey: return !closedGroupUpdate.senderKeys.isEmpty @@ -252,6 +252,7 @@ public final class ClosedGroupsProtocol : NSObject { } private static func handleNewGroupMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, using transaction: YapDatabaseReadWriteTransaction) { + let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue // Unwrap the message let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString() let name = closedGroupUpdate.name @@ -265,6 +266,25 @@ public final class ClosedGroupsProtocol : NSObject { let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: []) Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderKey.publicKey.toHexString(), ratchet: ratchet, using: transaction) } + // Sort out any discrepancies between the provided sender keys and what's required + let missingSenderKeys = Set(members).subtracting(senderKeys.map { $0.publicKey.toHexString() }) + let userPublicKey = getUserHexEncodedPublicKey() + if missingSenderKeys.contains(userPublicKey) { + establishSessionsIfNeeded(with: [String](missingSenderKeys), using: transaction) + 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)) + for member in members { + guard member != userPublicKey else { continue } + 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) + } + } + for publicKey in missingSenderKeys.subtracting([ userPublicKey ]) { + requestSenderKey(for: groupPublicKey, senderPublicKey: publicKey, using: transaction) + } // Create the group let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins)