diff --git a/src/chat/chat_poll.c b/src/chat/chat_poll.c index e3264141..51f72baa 100644 --- a/src/chat/chat_poll.c +++ b/src/chat/chat_poll.c @@ -1,5 +1,6 @@ #include "chat_poll.h" #include "chat_feedback.h" +#include "member_sync.h" #include "chat_core_priv.h" #include "chat_event.h" #include "../utun_instance.h" @@ -120,6 +121,10 @@ int chat_feedback_snapshot(struct UTUN_INSTANCE* inst, const char* channel, cons sqlite3_bind_blob(st, 1, message_id, 32, SQLITE_STATIC); while ((step = sqlite3_step(st)) == SQLITE_ROW) { uint64_t author = (uint64_t)sqlite3_column_int64(st, 0), ver = (uint64_t)sqlite3_column_int64(st, 2); + uint8_t author_key[32]; + enum ms_author_status status = member_sync_author_key(inst, channel, author, author_key); + if (status == MS_AUTHOR_ERROR) goto done; + if (status != MS_AUTHOR_ACTIVE) continue; const uint8_t* data = sqlite3_column_blob(st, 3); size_t len = sqlite3_column_bytes(st, 3); int kind = sqlite3_column_int(st, 1); if (kind == CHAT_FEEDBACK_REACTION) { @@ -191,6 +196,11 @@ void chat_feedback_check_message(struct UTUN_INSTANCE* inst, const char* channel if (sqlite3_prepare_v2(inst->topo_sqlite_db, sql, -1, &st, NULL) != SQLITE_OK) { poll_db_error(inst, "evaluate query"); return; } sqlite3_bind_blob(st, 1, message_id, 32, SQLITE_STATIC); int step; unsigned accepted = 0, rejected = 0; while ((step = sqlite3_step(st)) == SQLITE_ROW) { + uint8_t author_key[32]; + enum ms_author_status status = member_sync_author_key(inst, channel, + (uint64_t)sqlite3_column_int64(st, 0), author_key); + if (status == MS_AUTHOR_ERROR) { sqlite3_finalize(st); return; } + if (status != MS_AUTHOR_ACTIVE) continue; struct chat_poll_answer answer; if (chat_answer_decode(sqlite3_column_blob(st, 2), sqlite3_column_bytes(st, 2), &answer) < 0 || !is_poll || !poll_answer_allowed(&poll, &answer)) { diff --git a/src/chat/member_sync.c b/src/chat/member_sync.c index d8d65690..6dae5f65 100644 --- a/src/chat/member_sync.c +++ b/src/chat/member_sync.c @@ -1,5 +1,6 @@ #include "../routing_layer/topo_group_connect.h" #include "member_sync.h" +#include "chat_feedback.h" #include "../routing_layer/topo_node_sqlite.h" #include "../routing_layer/topo_group.h" @@ -740,6 +741,8 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id, /* ── recompute и подтвердить реальное изменение по хешу ── */ if (changed) { + /* Общий ключ может разрешить удостоверения приглашённых в других каналах. */ + if (chat_feedback_member_update(inst, m->node_id) < 0) return MT_ERR_IO; int rc = merkle_sync_recompute_path(inst, MT_DATA_MEMBERS, ch_id, m->node_id); if (rc < 0) return -1; if (rc == 0) changed = 0; /* запись была no-op (данные идентичны) */ @@ -752,6 +755,7 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id, void member_sync_record_committed(struct UTUN_INSTANCE* inst, const char* ns, uint64_t node_id) { merkle_sync_changed(inst, MT_DATA_MEMBERS, ns); + chat_feedback_member_committed(inst, node_id); struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)) : NULL; struct ETCP_CONN* conn = instance_find_conn(inst, node_id); if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) { @@ -946,7 +950,8 @@ int member_sync_verify_and_purge(struct UTUN_INSTANCE* inst, const char* ch_id) for (int i = 0; i < count; i++) if (topo_node_sqlite_member_del(db, ns, removed[i]) < 0) goto fail; stage = "index"; for (int i = 0; i < count; i++) - if (merkle_sync_recompute_path(inst, MT_DATA_MEMBERS, ns, removed[i]) < 0) goto fail; + if (merkle_sync_recompute_path(inst, MT_DATA_MEMBERS, ns, removed[i]) < 0 + || chat_feedback_member_update(inst, removed[i]) < 0) goto fail; stage = "commit"; rc = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); if (rc != SQLITE_OK) goto fail; @@ -956,6 +961,7 @@ int member_sync_verify_and_purge(struct UTUN_INSTANCE* inst, const char* ch_id) } for (int i = 0; i < count; i++) { uint64_t nid = removed[i]; + chat_feedback_member_committed(inst, nid); radio_forget_member_mute(inst, group_id, nid); struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, group_id) : NULL; struct ETCP_CONN* conn = instance_find_conn(inst, nid);