From 58c47bb24f7ac2196d7d26ef43ea0a15e4f5f7da Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 3 Nov 2026 23:19:22 +0100 Subject: [PATCH] Require current CHAT admission for history and sound settings --- src/chat/db_sync.c | 33 +++++++++++++++++++++++++++------ src/chat/db_sync.h | 4 ++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/chat/db_sync.c b/src/chat/db_sync.c index 512a5f88e..a10db2f27 100644 --- a/src/chat/db_sync.c +++ b/src/chat/db_sync.c @@ -731,13 +731,21 @@ static void db_message_result(void* ctx, const char* ns, uint64_t peer, int resu db->dispatch_depth--; db_done_sweep(db); db_release(si); } +/* Текущий допуск CHAT и точный ключ ETCP обязательны даже при старом READY. + * Настройки разрешены до готовности истории, но не через исключение MEMBERS/JOIN. */ +static int db_peer_allowed(struct DB_SYNC_INSTANCE* si, uint64_t peer) { + if (!si || !si->enabled) return 0; + struct UTUN_INSTANCE* inst = si->db_sync->inst; + struct ETCP_CONN* conn = instance_find_conn(inst, peer); + return conn && conn->links_up && !conn->close_requested && topo_group_chat_allowed(inst, si->group_id, peer) && + topo_node_sqlite_member_key_allowed(inst->topo_sqlite_db, si->ns, conn->crypto_ctx.peer_public_key); +} + static int db_message_peer(void* ctx, const char* ns, uint64_t peer) { struct UTUN_INSTANCE* inst = ctx; struct DB_SYNC_INSTANCE* si = db_sync_instance_find(inst, strtoull(ns, NULL, 10)); struct TOPO_GROUP* group = si ? topo_groups_find(inst->topo_groups, si->group_id) : NULL; - struct ETCP_CONN* conn = instance_find_conn(inst, peer); - return si && !si->sync_gated && !si->index.pending && topo_group_peer_ready(group, peer) && conn && - member_sync_validate_pubkey(inst, ns, conn->crypto_ctx.peer_public_key); + return si && !si->sync_gated && !si->index.pending && topo_group_peer_ready(group, peer) && db_peer_allowed(si, peer); } static int db_sync_peer_throttled(struct DB_SYNC* db, struct SI_PEER* p) { struct ETCP_CONN* conn = p && !p->sound_on ? instance_find_conn(db->inst, p->node_id) : NULL; @@ -931,7 +939,12 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* e) { if (!e) return; struct UTUN_INSTANCE* inst = conn ? conn->instance : NULL; struct DB_SYNC_INSTANCE* si = e->dgram && e->len >= 10 ? db_sync_instance_find(inst, db_read64(e->dgram + 1)) : NULL; - if (!si || !db_message_peer(inst, si->ns, conn->peer_node_id)) goto done; + if (!si || !db_message_peer(inst, si->ns, conn->peer_node_id)) { + DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "history receive denied group=%llu peer=%016llx type=%u bytes=%u: no current admission or readiness", + (unsigned long long)(e->dgram && e->len >= 9 ? db_read64(e->dgram + 1) : 0), + (unsigned long long)(conn ? conn->peer_node_id : 0), e->dgram && e->len >= 10 ? e->dgram[9] : 0, e->len); + goto done; + } const uint8_t* data = e->dgram + 10; size_t len = e->len - 10; si->holds++; if (e->dgram[9] == DB_MSG_ACK_PUSH) { @@ -1245,8 +1258,16 @@ void db_sync_peer_policy_changed(struct UTUN_INSTANCE* inst, uint64_t peer) { } void db_sync_set_peer_sound(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t peer, int sound) { struct DB_SYNC_INSTANCE* si = db_sync_instance_find(inst, group); - struct SI_PEER* p = si ? si_peer_add(si, peer) : NULL; - if (p) { p->sound_on = !!sound; db_sync_peer_policy_changed(inst, peer); } + if (!db_peer_allowed(si, peer)) { + DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "history SOUND_SETTING denied group=%llu peer=%016llx: no current CHAT admission", + (unsigned long long)group, (unsigned long long)peer); return; + } + struct SI_PEER* p = si_peer_add(si, peer); + if (!p) return; + p->sound_on = !!sound; + DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "history SOUND_SETTING accepted group=%llu peer=%016llx sound=%u", + (unsigned long long)group, (unsigned long long)peer, p->sound_on); + db_sync_peer_policy_changed(inst, peer); } void db_sync_members_changed(struct UTUN_INSTANCE* inst, const char* ns) { struct DB_SYNC* db = inst ? inst->db_sync : NULL; if (!db) return; diff --git a/src/chat/db_sync.h b/src/chat/db_sync.h index 9c25d2d39..6e88e8aa8 100644 --- a/src/chat/db_sync.h +++ b/src/chat/db_sync.h @@ -3,6 +3,9 @@ * общему Merkle-дереву; изменения рассылаются PUSH. Постоянный ключ — message_id, * порядок отображения — (timestamp, message_id). Подпись защищает весь конверт и data. * Ядро создаёт модуль, чат включает его и регистрирует таблицы каналов. + * Приём/отправка истории и её настройки требуют текущего допуска self/peer в живой + * CHAT-группе и точного ключа ETCP. Для истории дополнительно нужны READY и готовый + * индекс; исключения MEMBERS/JOIN не открывают ни PUSH/ACK, ни модель MESSAGES. * Обычно используется общая SQLite ядра; remove отключает таблицу от обмена, * сохраняя данные. Все вызовы и callbacks выполняются в потоке uasync. */ #ifndef DB_SYNC_H @@ -115,6 +118,7 @@ int db_sync_read_root(struct DB_SYNC_INSTANCE* si, uint8_t root[32]); void db_sync_peer_set_paused(struct DB_SYNC_INSTANCE* si, uint64_t node_id, int paused); // Per-(chat,peer) «play sound on message» flag: sound_off + sleeping peer → throttled. +/* Принять настройку от допущенного пира до/после синхронизации истории; отказ не создаёт состояние пира. */ void db_sync_set_peer_sound(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t peer_node_id, int sound_on); // До успешного member_sync блокирует входящий и исходящий обмен. После снятия