Accept prerelease private media payloads

This commit is contained in:
jack
2026-07-12 10:33:02 -04:00
parent 55f85d920c
commit 33a50d951a
4 changed files with 67 additions and 2 deletions
@@ -27,8 +27,17 @@ enum class NoisePayloadType(val value: UByte) {
companion object {
// #1434 prerelease iOS builds briefly emitted private files as 0x09. Keep this
// decode-only: every NoisePayload constructed by Android still encodes FILE_TRANSFER as
// its canonical 0x20 value, so the compatibility alias cannot leak into new traffic.
private val PRERELEASE_FILE_TRANSFER_RAW_VALUE = 0x09u.toUByte()
fun fromValue(value: UByte): NoisePayloadType? {
return values().find { it.value == value }
return if (value == PRERELEASE_FILE_TRANSFER_RAW_VALUE) {
FILE_TRANSFER
} else {
values().find { it.value == value }
}
}
}
}
@@ -210,6 +210,40 @@ class MessageHandlerTest {
}
}
@Test
fun `encrypted prerelease iOS Noise 0x09 private media is delivered`() {
runBlocking {
val file = BitchatFilePacket(
fileName = "prerelease-ios.pdf",
fileSize = 4,
mimeType = "application/pdf",
content = byteArrayOf(1, 2, 3, 4)
)
val prereleasePlaintext = byteArrayOf(0x09) + file.encode()!!
val ciphertext = byteArrayOf(0x41, 0x42, 0x43)
whenever(delegate.decryptFromPeer(any(), eq(peerID))).thenReturn(prereleasePlaintext)
whenever(delegate.getPeerNickname(peerID)).thenReturn(nickname)
whenever(delegate.getMyNickname()).thenReturn("me")
whenever(delegate.encryptForPeer(any(), eq(peerID))).thenReturn(byteArrayOf(0x55))
val outerPacket = BitchatPacket(
version = 2u,
type = MessageType.NOISE_ENCRYPTED.value,
senderID = peerID.hexToBytes(),
recipientID = myPeerID.hexToBytes(),
timestamp = System.currentTimeMillis().toULong(),
payload = ciphertext,
signature = signature,
ttl = 7u
)
handler.handleNoiseEncrypted(RoutedPacket(outerPacket, peerID, "direct-link"))
verify(delegate).decryptFromPeer(ciphertext, peerID)
verify(delegate).onMessageReceived(any())
}
}
private fun announcePacket(
ageMs: Long,
ttl: UByte = (AppConstants.MESSAGE_TTL_HOPS.toInt() - 1).toUByte(),
@@ -47,6 +47,18 @@ class PrivateMediaTransferPreparerTest {
assertEquals(0x20u.toUByte(), encryptedPlaintext!![0].toUByte())
}
@Test
fun `prerelease iOS Noise 0x09 decodes as file transfer but re-encodes canonical 0x20`() {
val filePayload = file(3).encode()!!
val prereleasePayload = byteArrayOf(0x09) + filePayload
val decoded = NoisePayload.decode(prereleasePayload)
assertEquals(NoisePayloadType.FILE_TRANSFER, decoded?.type)
assertTrue(filePayload.contentEquals(decoded?.data))
assertEquals(0x20u.toUByte(), decoded!!.encode()[0].toUByte())
}
@Test
fun `legacy mode requires consent and signing failure aborts`() {
val noConsent = preparer(policy = PrivateMediaPolicyDecision.RequiresLegacyConsent)
+11 -1
View File
@@ -11,7 +11,15 @@ for the recipient, and only then fragments the final outer packet.
- Noise payload data: one complete encoded `BitchatFilePacket`.
- Outer recipient: the target peer ID; never broadcast for private media.
Do not allocate a second Noise payload type for this format.
Prerelease iOS builds of #1434 briefly emitted the inner file type as `0x09`.
Android accepts that value on decode and immediately canonicalizes it to
`NoisePayloadType.FILE_TRANSFER`; every Android encode remains `0x20`. Do not
allocate or emit a second Noise payload type for this format.
The decode-only `0x09` alias may be removed only after every TestFlight/internal
build that emitted it has expired and the project's minimum-supported-client
policy excludes those builds. Track that release criterion explicitly; do not
remove the alias on an arbitrary calendar date.
## Capability announcement
@@ -96,6 +104,8 @@ capability and bounded streaming design.
- New Android to new iOS/Android: encrypted Noise `0x20` after authenticated
capability promotion.
- Prerelease iOS to new Android: encrypted Noise `0x09` is decoded,
canonicalized to `0x20`, and delivered during the migration window.
- New Android to a verified older client: blocked until the user explicitly
accepts one relay-visible signed raw `0x22` transfer.
- Old clients receiving a new announcement: ignore TLV `0x05` and continue