mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 19:25:20 +00:00
Fix decompression size limit to support max-sized file transfers
Root cause: BinaryProtocol.decode() was rejecting decompressed payloads larger than maxPayloadBytes (1 MB), but TLV-encoded file transfers are slightly larger due to metadata overhead. Fixes: - Changed decompression limit from maxPayloadBytes to maxFramedFileBytes - This accounts for TLV overhead (~50 bytes) + binary protocol headers - Now allows ~1.12 MB decompressed payloads (1 MB + overhead budget) The failing test was: - Creating 1 MB file content - TLV encoding adds ~50 bytes (1,048,627 total) - Compression reduces to ~1,084 bytes (highly repetitive data) - During decode, decompression was rejecting the 1,048,627 byte output - Now correctly allows it since 1,048,627 < 1,179,760 (maxFramedFileBytes) All 154 tests now pass including 'Max-sized file transfer survives reassembly'
This commit is contained in:
@@ -333,7 +333,8 @@ struct BinaryProtocol {
|
|||||||
originalSize = Int(rawSize)
|
originalSize = Int(rawSize)
|
||||||
}
|
}
|
||||||
// Guard to keep decompression bounded to sane BLE payload limits
|
// Guard to keep decompression bounded to sane BLE payload limits
|
||||||
guard originalSize >= 0 && originalSize <= FileTransferLimits.maxPayloadBytes else { return nil }
|
// Use maxFramedFileBytes to account for TLV overhead in file transfer payloads
|
||||||
|
guard originalSize >= 0 && originalSize <= FileTransferLimits.maxFramedFileBytes else { return nil }
|
||||||
let compressedSize = payloadLength - lengthFieldBytes
|
let compressedSize = payloadLength - lengthFieldBytes
|
||||||
guard compressedSize >= 0, let compressed = readData(compressedSize) else { return nil }
|
guard compressedSize >= 0, let compressed = readData(compressedSize) else { return nil }
|
||||||
|
|
||||||
|
|||||||
@@ -3395,7 +3395,7 @@ extension BLEService {
|
|||||||
if peerID == myPeerID {
|
if peerID == myPeerID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minimum header: 8 bytes ID + 2 index + 2 total + 1 type
|
// Minimum header: 8 bytes ID + 2 index + 2 total + 1 type
|
||||||
guard packet.payload.count >= 13 else { return }
|
guard packet.payload.count >= 13 else { return }
|
||||||
|
|
||||||
@@ -3441,10 +3441,11 @@ extension BLEService {
|
|||||||
}
|
}
|
||||||
return FileTransferLimits.maxPayloadBytes
|
return FileTransferLimits.maxPayloadBytes
|
||||||
}()
|
}()
|
||||||
guard currentSize + fragmentData.count <= assemblyLimit else {
|
let projectedSize = currentSize + fragmentData.count
|
||||||
|
guard projectedSize <= assemblyLimit else {
|
||||||
// Exceeds size limit - evict this assembly
|
// Exceeds size limit - evict this assembly
|
||||||
SecureLogger.warning(
|
SecureLogger.warning(
|
||||||
"🚫 Fragment assembly exceeds size limit (\(currentSize + fragmentData.count) bytes > \(assemblyLimit)), evicting",
|
"🚫 Fragment assembly exceeds size limit (\(projectedSize) bytes > \(assemblyLimit)), evicting. Type=\(originalType) Index=\(index)/\(total)",
|
||||||
category: .security
|
category: .security
|
||||||
)
|
)
|
||||||
incomingFragments.removeValue(forKey: key)
|
incomingFragments.removeValue(forKey: key)
|
||||||
@@ -3464,14 +3465,14 @@ extension BLEService {
|
|||||||
reassembled.append(fragment)
|
reassembled.append(fragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the original packet bytes we reassembled, so flags/compression are preserved
|
// Decode the original packet bytes we reassembled, so flags/compression are preserved
|
||||||
if let originalPacket = BinaryProtocol.decode(reassembled) {
|
if let originalPacket = BinaryProtocol.decode(reassembled) {
|
||||||
handleReceivedPacket(originalPacket, from: peerID)
|
handleReceivedPacket(originalPacket, from: peerID)
|
||||||
} else {
|
} else {
|
||||||
SecureLogger.error("❌ Failed to decode reassembled packet (type=\(originalType), total=\(total))", category: .session)
|
SecureLogger.error("❌ Failed to decode reassembled packet (type=\(originalType), total=\(total))", category: .session)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
incomingFragments.removeValue(forKey: key)
|
incomingFragments.removeValue(forKey: key)
|
||||||
fragmentMetadata.removeValue(forKey: key)
|
fragmentMetadata.removeValue(forKey: key)
|
||||||
|
|||||||
Reference in New Issue
Block a user