From b30670a67129f043145294693b1e812b6ec81bf6 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Sun, 2 Aug 2026 19:08:43 +0530 Subject: [PATCH 1/2] fix: raise iOS max decompressed payload size to match Android (10 MiB) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iOS's FileTransferLimits.maxFramedFileBytes was 1,179,760 bytes (~1.13 MiB) while Android's AppConstants.Protocol.MAX_PAYLOAD_LENGTH is 10,485,760 bytes (10 MiB). Since both platforms already enforce the same 50,000:1 compression- ratio guard independently, the lower iOS ceiling served no additional protection — it just caused legitimate large compressed messages from Android to be silently dropped on decode with no error surfaced to either side. Raise iOS's limit to 10 MiB to match Android's intended design ceiling. Fixes #1618 --- .../Sources/BitFoundation/FileTransferLimits.swift | 11 ++--------- .../BitFoundationTests/BinaryProtocolTests.swift | 11 +++++++++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift b/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift index 4c54f79c..40b20b10 100644 --- a/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift +++ b/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift @@ -7,15 +7,8 @@ public enum FileTransferLimits { /// Compressed images after downscaling should comfortably fit under this budget. public static let maxImageBytes: Int = 512 * 1024 // 512 KiB /// Worst-case size once TLV metadata and binary packet framing are included for the largest payloads. - public static let maxFramedFileBytes: Int = { - let maxMetadataBytes = Int(UInt16.max) * 2 // fileName + mimeType TLVs - let tlvEnvelopeOverhead = 18 + maxMetadataBytes // TLV tags + lengths + metadata bytes - let binaryEnvelopeOverhead = BinaryProtocol.v2HeaderSize - + BinaryProtocol.senderIDSize - + BinaryProtocol.recipientIDSize - + BinaryProtocol.signatureSize - return maxPayloadBytes + tlvEnvelopeOverhead + binaryEnvelopeOverhead - }() + /// MUST stay in sync with AppConstants.Protocol.MAX_PAYLOAD_LENGTH in the Android repo (issue #1618). + public static let maxFramedFileBytes: Int = 10_485_760 public static func isValidPayload(_ size: Int) -> Bool { size <= maxPayloadBytes diff --git a/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift b/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift index ddf7c8fc..78c6afa0 100644 --- a/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift +++ b/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift @@ -350,6 +350,17 @@ struct BinaryProtocolTests { #expect(BinaryProtocol.decode(encoded) == nil) } + @Test("Regression test for issue #1618: decode payload between 1.13 MiB and 10 MiB") + func payloadSizeBetweenOldAndNewLimit() throws { + let payloadSize = 2_000_000 + let payload = Data(repeating: 0x41, count: payloadSize) + let packet = TestHelpers.createTestPacket(payload: payload) + + let encodedData = try #require(BinaryProtocol.encode(packet), "Failed to encode packet") + let decodedPacket = try #require(BinaryProtocol.decode(encodedData), "Failed to decode packet") + #expect(decodedPacket.payload == payload) + } + // MARK: - Message Padding Tests @Test func messagePadding() throws { From d32021049e1b053cabe765374343fc72b161da35 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Mon, 3 Aug 2026 19:10:59 +0530 Subject: [PATCH 2/2] test: use v2 packet for regression test and add limit note --- .../Sources/BitFoundation/FileTransferLimits.swift | 1 + .../Tests/BitFoundationTests/BinaryProtocolTests.swift | 2 +- .../Tests/BitFoundationTests/TestHelpers.swift | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift b/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift index 40b20b10..aa6b9932 100644 --- a/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift +++ b/localPackages/BitFoundation/Sources/BitFoundation/FileTransferLimits.swift @@ -7,6 +7,7 @@ public enum FileTransferLimits { /// Compressed images after downscaling should comfortably fit under this budget. public static let maxImageBytes: Int = 512 * 1024 // 512 KiB /// Worst-case size once TLV metadata and binary packet framing are included for the largest payloads. + /// Note: This is now a hard expanded-size ceiling rather than the old tlv+frame formula. /// MUST stay in sync with AppConstants.Protocol.MAX_PAYLOAD_LENGTH in the Android repo (issue #1618). public static let maxFramedFileBytes: Int = 10_485_760 diff --git a/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift b/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift index 78c6afa0..b500afc4 100644 --- a/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift +++ b/localPackages/BitFoundation/Tests/BitFoundationTests/BinaryProtocolTests.swift @@ -354,7 +354,7 @@ struct BinaryProtocolTests { func payloadSizeBetweenOldAndNewLimit() throws { let payloadSize = 2_000_000 let payload = Data(repeating: 0x41, count: payloadSize) - let packet = TestHelpers.createTestPacket(payload: payload) + let packet = TestHelpers.createTestPacket(payload: payload, version: 2) let encodedData = try #require(BinaryProtocol.encode(packet), "Failed to encode packet") let decodedPacket = try #require(BinaryProtocol.decode(encodedData), "Failed to decode packet") diff --git a/localPackages/BitFoundation/Tests/BitFoundationTests/TestHelpers.swift b/localPackages/BitFoundation/Tests/BitFoundationTests/TestHelpers.swift index 7b2ff6a3..94817a26 100644 --- a/localPackages/BitFoundation/Tests/BitFoundationTests/TestHelpers.swift +++ b/localPackages/BitFoundation/Tests/BitFoundationTests/TestHelpers.swift @@ -56,7 +56,8 @@ final class TestHelpers { recipientID: PeerID? = nil, payload: Data = Data("test payload".utf8), signature: Data? = nil, - ttl: UInt8 = 3 + ttl: UInt8 = 3, + version: UInt8 = 1 ) -> BitchatPacket { return BitchatPacket( type: type, @@ -65,7 +66,8 @@ final class TestHelpers { timestamp: UInt64(Date().timeIntervalSince1970 * 1000), payload: payload, signature: signature, - ttl: ttl + ttl: ttl, + version: version ) }