diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index ed2908dbd..c1d081650 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4143,7 +4143,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4205,7 +4205,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4259,7 +4259,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4329,7 +4329,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4391,7 +4391,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4454,7 +4454,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 118; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4655,7 +4655,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 = 118; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4722,7 +4722,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 = 118; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", 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/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index 52a8b11a2..2a733ce34 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -235,8 +235,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 @@ -244,6 +244,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 @@ -257,6 +258,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) @@ -293,7 +313,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 ] }) 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. 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).") - }) - } }