From 7b3cfb6227c1519f46955ddbe750acab4e19d54d Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 4 Jul 2025 14:30:00 +0200 Subject: [PATCH] Fix Bluetooth errors and improve store-and-forward - Add peripheral state checks before all write operations - Fix 'can only accept commands while connected' errors - Check characteristic write properties to avoid ATT errors - Preserve original timestamps in store-and-forward messages - Only log crypto errors once per peer to reduce noise - Store-and-forward now correctly maintains message ordering The timestamp preservation ensures messages appear in the correct chronological order even when delivered later via store-and-forward. --- bitchat.xcodeproj/project.pbxproj | 16 ++++++--- bitchat/Info.plist | 6 +++- bitchat/Services/BluetoothMeshService.swift | 38 ++++++++++++--------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/bitchat.xcodeproj/project.pbxproj b/bitchat.xcodeproj/project.pbxproj index c5f1e7dc..0cbaf798 100644 --- a/bitchat.xcodeproj/project.pbxproj +++ b/bitchat.xcodeproj/project.pbxproj @@ -255,6 +255,7 @@ DEVELOPMENT_TEAM = L3N5LHJD5Y; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -264,9 +265,12 @@ PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_NAME = bitchat; SDKROOT = iphoneos; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + 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; }; @@ -282,6 +286,7 @@ DEVELOPMENT_TEAM = L3N5LHJD5Y; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = bitchat/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -291,9 +296,12 @@ PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_NAME = bitchat; SDKROOT = iphoneos; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + 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/Info.plist b/bitchat/Info.plist index 78b57dd9..08d8f420 100644 --- a/bitchat/Info.plist +++ b/bitchat/Info.plist @@ -41,9 +41,13 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown diff --git a/bitchat/Services/BluetoothMeshService.swift b/bitchat/Services/BluetoothMeshService.swift index 16ac85de..d4247640 100644 --- a/bitchat/Services/BluetoothMeshService.swift +++ b/bitchat/Services/BluetoothMeshService.swift @@ -35,6 +35,7 @@ class BluetoothMeshService: NSObject { private var activePeers: Set = [] // Track all active peers private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery + private var loggedCryptoErrors = Set() // Track which peers we've logged crypto errors for weak var delegate: BitchatDelegate? private let encryptionService = EncryptionService() @@ -210,6 +211,7 @@ class BluetoothMeshService: NSObject { self.broadcastPacket(messages[0]) } else if let dest = destination, let peripheral = self.connectedPeripherals[dest], + peripheral.state == .connected, let characteristic = self.peripheralCharacteristics[peripheral] { if let data = messages[0].toBinaryData() { peripheral.writeValue(data, for: characteristic, type: .withoutResponse) @@ -225,6 +227,7 @@ class BluetoothMeshService: NSObject { self?.broadcastPacket(message) } else if let dest = destination, let peripheral = self?.connectedPeripherals[dest], + peripheral.state == .connected, let characteristic = self?.peripheralCharacteristics[peripheral] { if let data = message.toBinaryData() { peripheral.writeValue(data, for: characteristic, type: .withoutResponse) @@ -627,9 +630,11 @@ class BluetoothMeshService: NSObject { // Also try targeted send if we have the peripheral if let peripheral = connectedPeripherals[peerID], + peripheral.state == .connected, let characteristic = peripheral.services?.first(where: { $0.uuid == BluetoothMeshService.serviceUUID })?.characteristics?.first(where: { $0.uuid == BluetoothMeshService.characteristicUUID }) { // Also sending targeted announce - peripheral.writeValue(data, for: characteristic, type: .withResponse) + let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.write) ? .withResponse : .withoutResponse + peripheral.writeValue(data, for: characteristic, type: writeType) } else { // No peripheral found for targeted send } @@ -768,10 +773,10 @@ class BluetoothMeshService: NSObject { } } - // Create stored message + // Create stored message with original packet timestamp preserved let storedMessage = StoredMessage( packet: packet, - timestamp: Date(), + timestamp: Date(timeIntervalSince1970: TimeInterval(packet.timestamp)), messageID: messageID, isForFavorite: isForFavorite ) @@ -850,21 +855,14 @@ class BluetoothMeshService: NSObject { guard let peripheral = peripheral, peripheral.state == .connected else { return } - // Create a new packet with fresh timestamp - let updatedPacket = BitchatPacket( - type: storedMessage.packet.type, - senderID: storedMessage.packet.senderID, - recipientID: storedMessage.packet.recipientID, - timestamp: UInt64(Date().timeIntervalSince1970), - payload: storedMessage.packet.payload, - signature: storedMessage.packet.signature, - ttl: storedMessage.packet.ttl - ) + // Send the original packet with preserved timestamp + // This maintains message ordering for store-and-forward + let packetToSend = storedMessage.packet - if let data = updatedPacket.toBinaryData(), + if let data = packetToSend.toBinaryData(), characteristic.properties.contains(.writeWithoutResponse) { peripheral.writeValue(data, for: characteristic, type: .withoutResponse) - // Sent cached message + // Sent cached message with original timestamp } } } @@ -1020,7 +1018,10 @@ class BluetoothMeshService: NSObject { return } } catch { - print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") + if !loggedCryptoErrors.contains(senderID) { + print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") + loggedCryptoErrors.insert(senderID) + } } } @@ -1084,7 +1085,10 @@ class BluetoothMeshService: NSObject { return } } catch { - print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") + if !loggedCryptoErrors.contains(senderID) { + print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") + loggedCryptoErrors.insert(senderID) + } } }