fix: ncd handle UAF in topo_recovery and topo_group_invite callbacks
topo_recovery_callback: detach cb on UP handoff and close handle on DOWN/TIMEOUT so no handle with cb_arg==ctx outlives ctx (ASAN heap-buffer-overflow in topo_recovery_callback). tgi_to_channel_cb: force_close handle on NCD_EVENT_TIMEOUT so a late UP cannot fire into the freed tgi_conn_ctx. Also: android chatgui reverseLayout scroll + msg order/stable pagination.
This commit is contained in:
1 parent
fc3295ce12
commit
9ee61dce6c
4 files changed
+19
-32
No files matched your search
@@ -18,7 +18,6 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.utun.chat.data.Channel
|
||||
@@ -112,31 +111,10 @@ fun ChatScreen(
|
||||
|
||||
val playbackState by viewModel.playbackState.collectAsState()
|
||||
|
||||
var initialScrolled by remember { mutableStateOf(false) }
|
||||
|
||||
/* своё сообщение — подтягиваемся вниз (в reverseLayout индекс 0 — это низ) */
|
||||
LaunchedEffect(messages.size) {
|
||||
if (messages.isEmpty()) return@LaunchedEffect
|
||||
val lastIndex = messages.size - 1
|
||||
if (!initialScrolled) {
|
||||
/* первый вход — мгновенный прыжок вниз без анимации */
|
||||
listState.scrollToItem(lastIndex)
|
||||
initialScrolled = true
|
||||
return@LaunchedEffect
|
||||
}
|
||||
/* новое сообщение: скроллим вниз если своё, либо если были у нижнего края */
|
||||
val ownMessage = messages.lastOrNull()?.isOutgoing == true
|
||||
val wasAtBottom = !listState.canScrollForward
|
||||
if (ownMessage || wasAtBottom) {
|
||||
listState.animateScrollToItem(lastIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/* при открытии клавиатуры прижимаем список к низу, чтобы последнее сообщение осталось видимым */
|
||||
val density = LocalDensity.current
|
||||
val imeVisible = WindowInsets.ime.getBottom(density) > 0
|
||||
LaunchedEffect(imeVisible) {
|
||||
if (imeVisible && messages.isNotEmpty()) {
|
||||
listState.scrollToItem(messages.size - 1)
|
||||
if (messages.lastOrNull()?.isOutgoing == true) {
|
||||
listState.scrollToItem(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,10 +133,12 @@ fun ChatScreen(
|
||||
)
|
||||
LazyColumn(
|
||||
modifier = Modifier.weight(1f).fillMaxWidth(),
|
||||
state = listState
|
||||
state = listState,
|
||||
reverseLayout = true
|
||||
) {
|
||||
items(messages.size) { idx ->
|
||||
MessageBubble(messages[idx], playbackState = playbackState,
|
||||
item { Spacer(Modifier.height(8.dp)) }
|
||||
items(messages.reversed()) { msg ->
|
||||
MessageBubble(msg, playbackState = playbackState,
|
||||
onPlayVoice = { path, durMs -> viewModel.playVoiceMessage(path, durMs) },
|
||||
onSeekVoice = { path, seekMs, durMs -> viewModel.seekVoice(path, seekMs, durMs) },
|
||||
onDownloadFile = { msg -> viewModel.downloadAttachment(msg) },
|
||||
@@ -171,7 +151,6 @@ fun ChatScreen(
|
||||
onOpenImage = { msg -> onViewPhoto(msg) },
|
||||
onPlayVideo = { msg -> onPlayVideo(msg) })
|
||||
}
|
||||
item { Spacer(Modifier.height(8.dp)) }
|
||||
}
|
||||
InputBar(
|
||||
text = text,
|
||||
|
||||
@@ -487,8 +487,12 @@ char* utun_bridge_get_messages_json(const char* channel_id, int limit) {
|
||||
char tbl_msg[80];
|
||||
msg_table_name(channel_id, tbl_msg, sizeof(tbl_msg));
|
||||
|
||||
char sql[256];
|
||||
snprintf(sql, sizeof(sql), "SELECT id, node_id, data, timestamp, local_attrs FROM \"%s\" ORDER BY timestamp ASC LIMIT %d", tbl_msg, limit);
|
||||
char sql[512];
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT id, node_id, data, timestamp, local_attrs FROM ("
|
||||
"SELECT id, node_id, data, timestamp, local_attrs, author_signature FROM \"%s\""
|
||||
" ORDER BY timestamp DESC, author_signature DESC LIMIT %d"
|
||||
") ORDER BY timestamp ASC, author_signature ASC", tbl_msg, limit);
|
||||
|
||||
sqlite3_stmt* st = NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) return u_strdup("[]");
|
||||
|
||||
Reference in new issue
Block a user