fix: NCD UAF, conn_mgr invite protocol, node_id derivation, link reuse
node_conn_direct: - ncd_init_cb: skip UP when links_up==0, ncd_up_cb delivers when link comes up - close/force_close: handle_count safety checks, callback clearing - open/open_node case 2: create links on reused dead conn - ncd_create_links: skip duplicate link on same conn (stale->etcp==conn) - set_callback: optional callback change on live handle conn_mgr: - cm_ncd_callback: DOWN only delivers event (handle stays alive) - cm_ncd_callback: TIMEOUT force_close BEFORE cm_deliver_event - cm_deliver_event: read handle fields to locals before callback (reentrany-safe) - INVITE_INFO_REQ/RESP: add duplicate cmd byte for direct-send protocol - cm_handle_invite_info_resp: search invite by group_id in channel conn_mgr Android: - node_id computed by sc_derive_node_id_from_pubkey in C, not Kotlin - utun_bridge_join_channel: recompute node_id, log mismatch - invite_link_c: compute nodeId from pubkey via sc_derive_node_id_from_pubkey - NativeLib.deriveNodeId, InviteLink.kt uses C function
This commit is contained in:
1 parent
4b07d59043
commit
740ed2a93a
10 files changed
+351
-53
No files matched your search
@@ -62,15 +62,6 @@ data class InviteData(
|
||||
object InviteLink {
|
||||
private const val PREFIX = "utun://"
|
||||
|
||||
fun deriveNodeId(pubkey: ByteArray): Long {
|
||||
val md = MessageDigest.getInstance("SHA-256")
|
||||
val hash = md.digest(pubkey)
|
||||
var id = 0L
|
||||
for (i in 0 until 8)
|
||||
id = (id shl 8) or (hash[i].toLong() and 0xFF)
|
||||
return id and 0x7FFFFFFFFFFFFFFFL
|
||||
}
|
||||
|
||||
fun decode(link: String): InviteData? {
|
||||
LogManager.addLog("DEBUG", "INVITE", "decode: ${link.take(80)}")
|
||||
if (!link.startsWith(PREFIX)) {
|
||||
@@ -140,7 +131,7 @@ object InviteLink {
|
||||
}
|
||||
|
||||
if (pubkey == null || pubkey.size != INVITE_PUBKEY_SIZE) return null
|
||||
val nodeId = deriveNodeId(pubkey)
|
||||
val nodeId = NativeLib.deriveNodeId(pubkey)
|
||||
val pkHex = pubkey.take(8).joinToString("") { "%02x".format(it) }
|
||||
LogManager.addLog("INFO", "INVITE", "decode: ch=0x%016x node=0x%016x pk=%s... addrs=%d".format(
|
||||
chId, nodeId, pkHex, addrs.size))
|
||||
|
||||
@@ -7,7 +7,6 @@ interface ChatEventCallback {
|
||||
}
|
||||
|
||||
object NativeLib {
|
||||
private var running = false
|
||||
|
||||
init {
|
||||
System.loadLibrary("utun")
|
||||
@@ -24,16 +23,13 @@ object NativeLib {
|
||||
|
||||
/** Start full uTun instance from INI config text */
|
||||
fun start(configText: String): Boolean {
|
||||
if (running) return true
|
||||
val ok = nativeStart(configText)
|
||||
if (ok) running = true
|
||||
return ok
|
||||
if (isReady()) return true
|
||||
return nativeStart(configText)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if (!running) return
|
||||
if (!isReady()) return
|
||||
nativeStop()
|
||||
running = false
|
||||
}
|
||||
|
||||
fun setEventCallback(cb: ChatEventCallback) {
|
||||
@@ -42,16 +38,13 @@ object NativeLib {
|
||||
})
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
nativeDestroy()
|
||||
running = false
|
||||
}
|
||||
fun destroy() { nativeDestroy() }
|
||||
|
||||
fun restart(dbPath: String, controlPort: Int, configText: String): Boolean {
|
||||
return nativeRestart(configText)
|
||||
}
|
||||
|
||||
fun isReady(): Boolean = running
|
||||
fun isReady(): Boolean = nativeIsRunning()
|
||||
|
||||
fun getMyNodeId(): Long = nativeGetMyNodeId()
|
||||
|
||||
@@ -66,6 +59,7 @@ object NativeLib {
|
||||
nativeJoinChannel(channelId, nodeId, pubkey, addrs, addrCount)
|
||||
LogManager.addLog("INFO", "JNI", "joinChannel: native returned")
|
||||
}
|
||||
fun deriveNodeId(pubkey: ByteArray): Long = nativeDeriveNodeId(pubkey)
|
||||
fun connectChannel(channelId: String) { nativeConnectChannel(channelId) }
|
||||
fun getChannels(): String = nativeGetChannels() ?: "[]"
|
||||
fun getMessages(channelId: String, limit: Int = 50): String = nativeGetMessages(channelId, limit) ?: "[]"
|
||||
@@ -124,6 +118,7 @@ object NativeLib {
|
||||
private external fun nativeCreateChannel(name: String, channelId: String)
|
||||
private external fun nativeConnectNode(address: String, port: Int, pubkeyHex: String)
|
||||
private external fun nativeJoinChannel(channelId: Long, nodeId: Long, pubkey: ByteArray, addrs: ByteArray, addrCount: Int)
|
||||
private external fun nativeDeriveNodeId(pubkey: ByteArray): Long
|
||||
private external fun nativeConnectChannel(channelId: String)
|
||||
private external fun nativeGetChannels(): String?
|
||||
private external fun nativeGetMessages(channelId: String, limit: Int): String?
|
||||
@@ -138,6 +133,7 @@ object NativeLib {
|
||||
private external fun nativeRestart(configText: String): Boolean
|
||||
private external fun nativePing()
|
||||
private external fun nativeIsResponsive(): Boolean
|
||||
private external fun nativeIsRunning(): Boolean
|
||||
|
||||
/* ── Channel members JNI ── */
|
||||
private external fun nativeGetChannelMembers(channelId: String): String?
|
||||
|
||||
@@ -95,7 +95,7 @@ class ChatViewModel : ViewModel() {
|
||||
viewModelScope.launch {
|
||||
while (isActive) {
|
||||
delay(3000)
|
||||
if (!dbReady || !NativeLib.isReady()) continue
|
||||
if (!dbReady || !NativeLib.isReady()) { _isStuck.value = true; continue }
|
||||
NativeLib.ping()
|
||||
delay(100)
|
||||
_isStuck.value = !NativeLib.isResponsive()
|
||||
|
||||
Reference in new issue
Block a user