mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 02:25:20 +00:00
Remove voice memo references and improve duplicate message prevention
- Remove NSMicrophoneUsageDescription from Info.plist and project.yml - Add millisecond timestamps to prevent same-second message collisions - Include payload hash in message ID for absolute uniqueness - Add recentlySentMessages tracking to prevent any duplicate sends - Reduce retries from 2 to 1 for broadcast messages - Clean up sent message tracking after 10 seconds
This commit is contained in:
@@ -26,8 +26,6 @@
|
|||||||
<string>bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users.</string>
|
<string>bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users.</string>
|
||||||
<key>NSBluetoothPeripheralUsageDescription</key>
|
<key>NSBluetoothPeripheralUsageDescription</key>
|
||||||
<string>bitchat uses Bluetooth to discover and connect with other bitchat users nearby.</string>
|
<string>bitchat uses Bluetooth to discover and connect with other bitchat users nearby.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
|
||||||
<string>bitchat needs access to your microphone to record voice notes.</string>
|
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>bluetooth-central</string>
|
<string>bluetooth-central</string>
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
private var deliveredMessages: Set<String> = [] // Track delivered message IDs to prevent duplicates
|
private var deliveredMessages: Set<String> = [] // Track delivered message IDs to prevent duplicates
|
||||||
private var cachedMessagesSentToPeer: Set<String> = [] // Track which peers have already received cached messages
|
private var cachedMessagesSentToPeer: Set<String> = [] // Track which peers have already received cached messages
|
||||||
private var receivedMessageTimestamps: [String: Date] = [:] // Track timestamps of received messages for debugging
|
private var receivedMessageTimestamps: [String: Date] = [:] // Track timestamps of received messages for debugging
|
||||||
|
private var recentlySentMessages: Set<String> = [] // Short-term cache to prevent any duplicate sends
|
||||||
|
|
||||||
// Battery and range optimizations
|
// Battery and range optimizations
|
||||||
private var scanDutyCycleTimer: Timer?
|
private var scanDutyCycleTimer: Timer?
|
||||||
@@ -516,26 +517,34 @@ class BluetoothMeshService: NSObject {
|
|||||||
type: MessageType.message.rawValue,
|
type: MessageType.message.rawValue,
|
||||||
senderID: Data(self.myPeerID.utf8),
|
senderID: Data(self.myPeerID.utf8),
|
||||||
recipientID: SpecialRecipients.broadcast, // Special broadcast ID
|
recipientID: SpecialRecipients.broadcast, // Special broadcast ID
|
||||||
timestamp: UInt64(Date().timeIntervalSince1970),
|
timestamp: UInt64(Date().timeIntervalSince1970 * 1000), // milliseconds
|
||||||
payload: messageData,
|
payload: messageData,
|
||||||
signature: signature,
|
signature: signature,
|
||||||
ttl: self.adaptiveTTL
|
ttl: self.adaptiveTTL
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add random delay before initial send
|
// Track this message to prevent duplicate sends
|
||||||
let initialDelay = self.randomDelay()
|
let msgID = "\(packet.timestamp)-\(self.myPeerID)-\(packet.payload.prefix(32).hashValue)"
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + initialDelay) { [weak self] in
|
if !self.recentlySentMessages.contains(msgID) {
|
||||||
self?.broadcastPacket(packet)
|
self.recentlySentMessages.insert(msgID)
|
||||||
// Sending message
|
|
||||||
}
|
// Clean up old entries after 10 seconds
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) { [weak self] in
|
||||||
// Retry with randomized delays for reliability
|
self?.recentlySentMessages.remove(msgID)
|
||||||
let baseDelays = [0.2, 0.5]
|
}
|
||||||
for baseDelay in baseDelays {
|
|
||||||
let jitteredDelay = baseDelay + self.randomDelay()
|
// Add random delay before initial send
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + jitteredDelay) { [weak self] in
|
let initialDelay = self.randomDelay()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + initialDelay) { [weak self] in
|
||||||
self?.broadcastPacket(packet)
|
self?.broadcastPacket(packet)
|
||||||
// Re-sending message with jitter
|
// Sending message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single retry for reliability
|
||||||
|
let retryDelay = 0.3 + self.randomDelay()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + retryDelay) { [weak self] in
|
||||||
|
self?.broadcastPacket(packet)
|
||||||
|
// Re-sending message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +602,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
type: MessageType.message.rawValue,
|
type: MessageType.message.rawValue,
|
||||||
senderID: Data(self.myPeerID.utf8),
|
senderID: Data(self.myPeerID.utf8),
|
||||||
recipientID: Data(recipientPeerID.utf8),
|
recipientID: Data(recipientPeerID.utf8),
|
||||||
timestamp: UInt64(Date().timeIntervalSince1970),
|
timestamp: UInt64(Date().timeIntervalSince1970 * 1000), // milliseconds
|
||||||
payload: encryptedPayload,
|
payload: encryptedPayload,
|
||||||
signature: signature,
|
signature: signature,
|
||||||
ttl: self.adaptiveTTL
|
ttl: self.adaptiveTTL
|
||||||
@@ -614,14 +623,25 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add random delay for timing obfuscation
|
// Track to prevent duplicate sends
|
||||||
let delay = self.randomDelay()
|
let msgID = "\(packet.timestamp)-\(self.myPeerID)-\(packet.payload.prefix(32).hashValue)"
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
if !self.recentlySentMessages.contains(msgID) {
|
||||||
self?.broadcastPacket(packet)
|
self.recentlySentMessages.insert(msgID)
|
||||||
// Private message sent with timing delay
|
|
||||||
|
// Clean up after 10 seconds
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) { [weak self] in
|
||||||
|
self?.recentlySentMessages.remove(msgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add random delay for timing obfuscation
|
||||||
|
let delay = self.randomDelay()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
|
self?.broadcastPacket(packet)
|
||||||
|
// Private message sent with timing delay
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't call didReceiveMessage here - let the view model handle it directly
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't call didReceiveMessage here - let the view model handle it directly
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -801,7 +821,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Create stored message with original packet timestamp preserved
|
// Create stored message with original packet timestamp preserved
|
||||||
let storedMessage = StoredMessage(
|
let storedMessage = StoredMessage(
|
||||||
packet: packet,
|
packet: packet,
|
||||||
timestamp: Date(timeIntervalSince1970: TimeInterval(packet.timestamp)),
|
timestamp: Date(timeIntervalSince1970: TimeInterval(packet.timestamp) / 1000.0), // convert from milliseconds
|
||||||
messageID: messageID,
|
messageID: messageID,
|
||||||
isForFavorite: isForFavorite
|
isForFavorite: isForFavorite
|
||||||
)
|
)
|
||||||
@@ -1042,10 +1062,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replay attack protection: Check timestamp is within reasonable window (5 minutes)
|
// Replay attack protection: Check timestamp is within reasonable window (5 minutes)
|
||||||
let currentTime = UInt64(Date().timeIntervalSince1970)
|
let currentTime = UInt64(Date().timeIntervalSince1970 * 1000) // milliseconds
|
||||||
let timeDiff = abs(Int64(currentTime) - Int64(packet.timestamp))
|
let timeDiff = abs(Int64(currentTime) - Int64(packet.timestamp))
|
||||||
if timeDiff > 300 { // 5 minutes
|
if timeDiff > 300000 { // 5 minutes in milliseconds
|
||||||
print("[SECURITY] Dropping packet with timestamp too far from current time: \(timeDiff) seconds")
|
print("[SECURITY] Dropping packet with timestamp too far from current time: \(timeDiff/1000) seconds")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,7 +1077,8 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Include both type and payload hash for fragments to ensure uniqueness
|
// Include both type and payload hash for fragments to ensure uniqueness
|
||||||
messageID = "\(packet.timestamp)-\(String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) ?? "")-\(packet.type)-\(packet.payload.hashValue)"
|
messageID = "\(packet.timestamp)-\(String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) ?? "")-\(packet.type)-\(packet.payload.hashValue)"
|
||||||
} else {
|
} else {
|
||||||
messageID = "\(packet.timestamp)-\(String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) ?? "")"
|
// Include payload hash for absolute uniqueness (handles same-second messages)
|
||||||
|
messageID = "\(packet.timestamp)-\(String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) ?? "")-\(packet.payload.prefix(64).hashValue)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use bloom filter for efficient duplicate detection
|
// Use bloom filter for efficient duplicate detection
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ targets:
|
|||||||
LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET)
|
LSMinimumSystemVersion: $(MACOSX_DEPLOYMENT_TARGET)
|
||||||
NSBluetoothAlwaysUsageDescription: bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users.
|
NSBluetoothAlwaysUsageDescription: bitchat uses Bluetooth to create a secure mesh network for chatting with nearby users.
|
||||||
NSBluetoothPeripheralUsageDescription: bitchat uses Bluetooth to discover and connect with other bitchat users nearby.
|
NSBluetoothPeripheralUsageDescription: bitchat uses Bluetooth to discover and connect with other bitchat users nearby.
|
||||||
NSMicrophoneUsageDescription: bitchat needs access to your microphone to record voice notes.
|
|
||||||
UIBackgroundModes:
|
UIBackgroundModes:
|
||||||
- bluetooth-central
|
- bluetooth-central
|
||||||
- bluetooth-peripheral
|
- bluetooth-peripheral
|
||||||
|
|||||||
Reference in New Issue
Block a user