From 6afef8466a61215b7cab409908397f8df734f4c6 Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 25 Jul 2025 18:09:55 +0200 Subject: [PATCH] Fix read receipt to use same efficient pattern as delivery ACK - Modified read receipt to use type marker + binary payload pattern - Added read receipt type marker handling in noise decryption - Reduces message size and processing overhead - Ensures consistency between delivery ACK and read receipt implementations --- bitchat.xcodeproj/project.pbxproj | 4 +- bitchat/Services/BluetoothMeshService.swift | 69 ++++++++++++--------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/bitchat.xcodeproj/project.pbxproj b/bitchat.xcodeproj/project.pbxproj index 0c33af40..0c04f530 100644 --- a/bitchat.xcodeproj/project.pbxproj +++ b/bitchat.xcodeproj/project.pbxproj @@ -785,7 +785,7 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -841,7 +841,7 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; diff --git a/bitchat/Services/BluetoothMeshService.swift b/bitchat/Services/BluetoothMeshService.swift index f14b56a8..d5a20bb0 100644 --- a/bitchat/Services/BluetoothMeshService.swift +++ b/bitchat/Services/BluetoothMeshService.swift @@ -1502,41 +1502,35 @@ class BluetoothMeshService: NSObject { // Check if we have a Noise session with this peer // Use noiseService directly if self.noiseService.hasEstablishedSession(with: recipientID) { - // Use Noise encryption - send as Noise encrypted message + // Use Noise encryption - encrypt only the receipt payload directly do { - // Create inner read receipt packet - let innerPacket = BitchatPacket( - type: MessageType.readReceipt.rawValue, + // Create a special payload that indicates this is a read receipt + // Format: [1 byte type marker] + [receipt binary data] + var receiptPayload = Data() + receiptPayload.append(MessageType.readReceipt.rawValue) // Type marker + receiptPayload.append(receiptData) // Receipt binary data + + // Encrypt only the payload (not a full packet) + let encryptedPayload = try noiseService.encrypt(receiptPayload, for: recipientID) + + // Create outer Noise packet with the encrypted payload + let outerPacket = BitchatPacket( + type: MessageType.noiseEncrypted.rawValue, senderID: Data(hexString: self.myPeerID) ?? Data(), recipientID: Data(hexString: recipientID) ?? Data(), timestamp: UInt64(Date().timeIntervalSince1970 * 1000), - payload: receiptData, + payload: encryptedPayload, signature: nil, ttl: 3 ) - // Encrypt the entire inner packet - if let innerData = innerPacket.toBinaryData() { - let encryptedInnerData = try noiseService.encrypt(innerData, for: recipientID) - - // Create outer Noise packet - let outerPacket = BitchatPacket( - type: MessageType.noiseEncrypted.rawValue, - senderID: Data(hexString: self.myPeerID) ?? Data(), - recipientID: Data(hexString: recipientID) ?? Data(), - timestamp: UInt64(Date().timeIntervalSince1970 * 1000), - payload: encryptedInnerData, - signature: nil, - ttl: 3 ) - - SecureLogger.log("Sending encrypted read receipt for message \(receipt.originalMessageID) to \(recipientID)", category: SecureLogger.noise, level: .info) - - // Try direct delivery first for read receipts - if !self.sendDirectToRecipient(outerPacket, recipientPeerID: recipientID) { - // Recipient not directly connected, use selective relay - SecureLogger.log("Recipient \(recipientID) not directly connected for read receipt, using relay", - category: SecureLogger.session, level: .info) - self.sendViaSelectiveRelay(outerPacket, recipientPeerID: recipientID) - } + SecureLogger.log("Sending encrypted read receipt for message \(receipt.originalMessageID) to \(recipientID)", category: SecureLogger.noise, level: .info) + + // Try direct delivery first for read receipts + if !self.sendDirectToRecipient(outerPacket, recipientPeerID: recipientID) { + // Recipient not directly connected, use selective relay + SecureLogger.log("Recipient \(recipientID) not directly connected for read receipt, using relay", + category: SecureLogger.session, level: .info) + self.sendViaSelectiveRelay(outerPacket, recipientPeerID: recipientID) } } catch { SecureLogger.logError(error, context: "Failed to encrypt read receipt via Noise for \(recipientID)", category: SecureLogger.encryption) @@ -5358,6 +5352,25 @@ extension BluetoothMeshService: CBPeripheralManagerDelegate { SecureLogger.log("Failed to decode delivery ACK via Noise - data size: \(ackData.count)", category: SecureLogger.session, level: .warning) } } + + // Check if this is a read receipt with the new format + else if typeMarker == MessageType.readReceipt.rawValue { + // Extract the receipt binary data (skip the type marker) + let receiptData = decryptedData.dropFirst() + + // Decode the read receipt from binary + if let receipt = ReadReceipt.fromBinaryData(receiptData) { + SecureLogger.log("Received binary read receipt via Noise: \(receipt.originalMessageID) from \(receipt.readerNickname)", category: SecureLogger.session, level: .debug) + + // Process the read receipt + DispatchQueue.main.async { + self.delegate?.didReceiveReadReceipt(receipt) + } + return + } else { + SecureLogger.log("Failed to decode read receipt via Noise - data size: \(receiptData.count)", category: SecureLogger.session, level: .warning) + } + } } // Try to parse as a full inner packet (for backward compatibility and other message types)