mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
Merge 371c123910ef9ca4c3bf16063e83fff839cff3e2 into c127eb83ab94c069c32d37530d2faecd381cd2a8
This commit is contained in:
commit
f046f3f9f2
@ -852,6 +852,34 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
|
||||
return reusable
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mesh timeline stays UTF-8 for iOS interop. Channel messages use the shared
|
||||
* [BitchatMessage] binary envelope so receivers can route by `channel`.
|
||||
*/
|
||||
private fun encodePublicOrChannelPayload(
|
||||
content: String,
|
||||
mentions: List<String>,
|
||||
channel: String?
|
||||
): ByteArray {
|
||||
if (channel == null) return content.toByteArray(Charsets.UTF_8)
|
||||
val nickname = try {
|
||||
com.bitchat.android.services.NicknameProvider.getNickname(context, myPeerID)
|
||||
} catch (_: Exception) {
|
||||
myPeerID
|
||||
}
|
||||
val encoded = BitchatMessage(
|
||||
sender = nickname,
|
||||
content = content,
|
||||
timestamp = java.util.Date(),
|
||||
isRelay = false,
|
||||
senderPeerID = myPeerID,
|
||||
mentions = mentions.takeIf { it.isNotEmpty() },
|
||||
channel = channel
|
||||
).toBinaryPayload()
|
||||
return encoded ?: content.toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send public message
|
||||
*/
|
||||
@ -859,13 +887,14 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
|
||||
if (content.isEmpty()) return
|
||||
|
||||
serviceScope.launch {
|
||||
val payloadBytes = encodePublicOrChannelPayload(content, mentions, channel)
|
||||
val packet = BitchatPacket(
|
||||
version = 1u,
|
||||
type = MessageType.MESSAGE.value,
|
||||
senderID = hexStringToByteArray(myPeerID),
|
||||
recipientID = SpecialRecipients.BROADCAST,
|
||||
timestamp = System.currentTimeMillis().toULong(),
|
||||
payload = content.toByteArray(Charsets.UTF_8),
|
||||
payload = payloadBytes,
|
||||
signature = null,
|
||||
ttl = MAX_TTL
|
||||
)
|
||||
|
||||
@ -530,16 +530,42 @@ class MeshCore(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mesh timeline stays UTF-8 for iOS interop. Channel messages use the shared
|
||||
* [BitchatMessage] binary envelope so receivers can route by `channel` instead
|
||||
* of dumping every #room into the public Mesh feed.
|
||||
*/
|
||||
private fun encodePublicOrChannelPayload(
|
||||
content: String,
|
||||
mentions: List<String>,
|
||||
channel: String?
|
||||
): ByteArray {
|
||||
if (channel == null) return content.toByteArray(Charsets.UTF_8)
|
||||
val nickname = hooks.announcementNicknameProvider?.invoke() ?: myPeerID
|
||||
val encoded = BitchatMessage(
|
||||
sender = nickname,
|
||||
content = content,
|
||||
timestamp = java.util.Date(),
|
||||
isRelay = false,
|
||||
senderPeerID = myPeerID,
|
||||
mentions = mentions.takeIf { it.isNotEmpty() },
|
||||
channel = channel
|
||||
).toBinaryPayload()
|
||||
return encoded ?: content.toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
|
||||
fun sendMessage(content: String, mentions: List<String> = emptyList(), channel: String? = null) {
|
||||
if (content.isEmpty()) return
|
||||
scope.launch {
|
||||
val payloadBytes = encodePublicOrChannelPayload(content, mentions, channel)
|
||||
val packet = BitchatPacket(
|
||||
version = 1u,
|
||||
type = MessageType.MESSAGE.value,
|
||||
senderID = MeshPacketUtils.hexStringToByteArray(myPeerID),
|
||||
recipientID = SpecialRecipients.BROADCAST,
|
||||
timestamp = System.currentTimeMillis().toULong(),
|
||||
payload = content.toByteArray(Charsets.UTF_8),
|
||||
payload = payloadBytes,
|
||||
signature = null,
|
||||
ttl = maxTtl
|
||||
)
|
||||
|
||||
@ -484,10 +484,20 @@ class MessageHandler(private val myPeerID: String, private val appContext: andro
|
||||
Log.w(TAG, "FILE_TRANSFER decode failed (broadcast) from ${peerID.take(8)}")
|
||||
}
|
||||
|
||||
// Fallback: plain text
|
||||
val message = BitchatMessage(
|
||||
id = PacketIdUtil.computeIdHex(packet).uppercase(),
|
||||
sender = delegate?.getPeerNickname(peerID) ?: "unknown",
|
||||
// Prefer the shared binary envelope (channel / mentions). Fall back to
|
||||
// legacy UTF-8 mesh text for older peers and for iOS public broadcasts.
|
||||
val packetId = PacketIdUtil.computeIdHex(packet).uppercase()
|
||||
val peerNickname = delegate?.getPeerNickname(peerID) ?: "unknown"
|
||||
val message = BitchatMessage.fromBinaryPayload(packet.payload)?.let { decoded ->
|
||||
decoded.copy(
|
||||
id = packetId,
|
||||
sender = decoded.sender.ifBlank { peerNickname },
|
||||
senderPeerID = peerID,
|
||||
timestamp = Date(packet.timestamp.toLong())
|
||||
)
|
||||
} ?: BitchatMessage(
|
||||
id = packetId,
|
||||
sender = peerNickname,
|
||||
content = String(packet.payload, Charsets.UTF_8),
|
||||
senderPeerID = peerID,
|
||||
timestamp = Date(packet.timestamp.toLong())
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.bitchat.android.model
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.util.Date
|
||||
|
||||
class ChannelWireFormatTest {
|
||||
@Test
|
||||
fun channelFlagSurvivesBinaryRoundTrip() {
|
||||
val original = BitchatMessage(
|
||||
sender = "alice",
|
||||
content = "hello channel",
|
||||
timestamp = Date(1_700_000_000_000L),
|
||||
senderPeerID = "aabbccddeeff0011",
|
||||
channel = "#general"
|
||||
)
|
||||
val encoded = original.toBinaryPayload()
|
||||
assertNotNull(encoded)
|
||||
// Must not be plain UTF-8 of the content alone — that is the mesh leak.
|
||||
assertTrue(encoded!!.size > original.content.toByteArray(Charsets.UTF_8).size)
|
||||
|
||||
val decoded = BitchatMessage.fromBinaryPayload(encoded)
|
||||
assertNotNull(decoded)
|
||||
assertEquals("#general", decoded!!.channel)
|
||||
assertEquals("hello channel", decoded.content)
|
||||
assertEquals("alice", decoded.sender)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plainUtf8MeshPayloadDoesNotParseAsChannelEnvelope() {
|
||||
val plain = "just a mesh hello".toByteArray(Charsets.UTF_8)
|
||||
assertNull(BitchatMessage.fromBinaryPayload(plain))
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user