Authorize member disclosure separately from recovery requests and clean abandoned versions

This commit is contained in:
evgeny committed 2026-11-04 00:45:06 +01:00
1 parent fcff5c626b
commit 1aa528d352
2 files changed
+31 -5

No files matched your search

+30 -4
View File
@@ -1611,10 +1611,27 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer, co
}
static int _member_validate_peer(void* ctx, const char* ns, uint64_t peer) {
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)ctx;
sqlite3* db = _db(inst);
if (!db) return 0;
return topo_node_sqlite_member_in_channel(db, ns, peer);
struct UTUN_INSTANCE* inst = ctx;
struct ETCP_CONN* conn = inst ? instance_find_conn(inst, peer) : NULL;
return conn && conn->initialized && conn->links_up && conn->state != 2 && !conn->close_requested &&
topo_group_chat_allowed(inst, chat_channel_id(ns), peer) &&
topo_node_sqlite_member_key_allowed(_db(inst), ns, conn->peer_pubkey);
}
/* Разрешение только спросить: канал выбран локально, ключ источника уже связан с его JOIN.
* Никаких страниц/хешей в ответ этот режим не выдаёт; источник сам проверяет наш допуск. */
static int member_validate_request(void* ctx, const char* ns, uint64_t peer) {
struct UTUN_INSTANCE* inst = ctx;
struct TOPO_GROUP* group = inst && inst->topo_groups ? topo_groups_find(inst->topo_groups, chat_channel_id(ns)) : NULL;
struct ETCP_CONN* conn = inst ? instance_find_conn(inst, peer) : NULL;
if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT || group->stopping || strcmp(group->channel_id, ns) ||
!conn || !conn->initialized || !conn->links_up || conn->state == 2 || conn->close_requested) return 0;
struct member_saved record;
int found = member_read_saved(_db(inst), ns, peer, 0, 0, &record);
if (found != 1 || record.source || record.malformed || memcmp(record.x, conn->peer_pubkey, 32) ||
sc_derive_node_id_from_pubkey(record.x) != peer || _verify_join_sig(_db(inst), ns, &record.rec) != 1) return 0;
uint8_t key[32]; enum ms_author_status status = member_sync_author_key(inst, ns, peer, key);
return status == MS_AUTHOR_ACTIVE || status == MS_AUTHOR_PENDING;
}
static int member_finish(void* ctx, const char* ns) {
@@ -1690,6 +1707,7 @@ static const struct merkle_sync_data_ops g_member_ops = {
.get_page = _member_get_page,
.apply_items = _member_apply_items,
.validate_peer = _member_validate_peer,
.validate_request = member_validate_request,
.finish = member_finish,
.on_result = member_policy_result,
.begin_pull = member_begin_pull,
@@ -1716,6 +1734,10 @@ static int _rebuild_all_trees(struct UTUN_INSTANCE* inst) {
}
uint64_t mask = merkle_sync_level_prefix(UINT64_MAX, MT_MAX_LEVEL);
char sql[256];
snprintf(sql, sizeof(sql), "DELETE FROM \"%s\" WHERE record_state<>0", table);
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) { rc = SQLITE_ERROR; break; }
if (sqlite3_changes(db)) DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "member receive abandoned versions removed ch=%s rows=%d",
ns, sqlite3_changes(db));
snprintf(sql, sizeof(sql), "SELECT DISTINCT (node_id & %lld) FROM \"%s\" WHERE record_state=0 AND source=0", (long long)mask, table);
sqlite3_stmt* leaves = NULL;
int lr = sqlite3_prepare_v2(db, sql, -1, &leaves, NULL);
@@ -1829,6 +1851,10 @@ void member_sync_destroy(struct UTUN_INSTANCE* inst) {
int member_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
const char* ch_id, merkle_sync_done_cb done_cb, void* arg) {
if (!_member_validate_peer(inst, ch_id, peer) && !member_validate_request(inst, ch_id, peer)) {
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "member start denied ch=%s peer=%016llx", ch_id ? ch_id : "-", (unsigned long long)peer);
return -1;
}
if (member_sync_verify_and_purge(inst, ch_id) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: start rejected after purge failure ns=%s peer=%016llx",
MS_ID, ch_id ? ch_id : "-", (unsigned long long)peer); return -1;
+1 -1
View File
@@ -25,7 +25,7 @@ static void media_test_group(struct UTUN_INSTANCE* inst, uint64_t id, const uint
if (queue_data_put_with_index(inst->topo_groups->group_list, &g->ll)) abort();
}
char sql[512];
snprintf(sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS peers_%llu(node_id INTEGER PRIMARY KEY,source INTEGER DEFAULT 0,"
snprintf(sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS peers_%llu(node_id INTEGER PRIMARY KEY,record_state INTEGER DEFAULT 0,source INTEGER DEFAULT 0,"
"deleted INTEGER DEFAULT 0,admitted INTEGER DEFAULT 1,node_type INTEGER DEFAULT 0,adm_tags TEXT DEFAULT '{}')",
(unsigned long long)id);
if (sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) != SQLITE_OK) abort();