mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 11:25:21 +00:00
Accept prerelease private media payloads
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user