diff --git a/src/Makefile.am b/src/Makefile.am index 9fe74d032..18943ed77 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -189,6 +189,7 @@ utun_CORE_SOURCES = \ chat/chat_devgroup_invite.c \ chat/chat_devgroup.h \ chat/group_avatar.c \ + chat/group_policy.c \ chat/chat_status.c \ chat/chat_sync.c \ chat/chat_admin.c \ @@ -397,6 +398,7 @@ libutun_a_SOURCES = \ chat/chat_devgroup_invite.c \ chat/chat_devgroup.h \ chat/group_avatar.c \ + chat/group_policy.c \ chat/chat_status.c \ chat/chat_sync.c \ chat/chat_admin.c \ diff --git a/src/routing_layer/topo_node_sqlite.c b/src/routing_layer/topo_node_sqlite.c index 21fed3d19..b424d4620 100644 --- a/src/routing_layer/topo_node_sqlite.c +++ b/src/routing_layer/topo_node_sqlite.c @@ -391,6 +391,8 @@ int topo_node_sqlite_init(sqlite3* db) { "CREATE UNIQUE INDEX IF NOT EXISTS idx_na_unique ON node_addresses(node_id,family,socket_id,protocol,address,port,address_kind);" "CREATE INDEX IF NOT EXISTS idx_na_addr_lookup ON node_addresses(family, address, port, socket_id);" + "CREATE TABLE IF NOT EXISTS group_policy(channel_id TEXT PRIMARY KEY,version INTEGER NOT NULL," + "all_members INTEGER NOT NULL,signature BLOB NOT NULL);" "CREATE TABLE IF NOT EXISTS channels (" " channel_id TEXT PRIMARY KEY," // ID канала " name TEXT NOT NULL," // Название канала @@ -515,16 +517,23 @@ int topo_node_sqlite_member_local_init(sqlite3* db, const char* channel_id) { if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "radio: inspect member schema ch=%s: %s", channel_id, sqlite3_errmsg(db)); return -1; } - int has_radio_muted = 0, rc; + int has_radio_muted = 0, has_admitted = 0, rc; while ((rc = sqlite3_step(st)) == SQLITE_ROW) { const char* column = (const char*)sqlite3_column_text(st, 1); if (column && !strcmp(column, "radio_muted")) has_radio_muted = 1; + if (column && !strcmp(column, "admitted")) has_admitted = 1; } int final = sqlite3_finalize(st); if (rc != SQLITE_DONE || final != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "radio: read member schema ch=%s step=%d finalize=%d: %s", channel_id, rc, final, sqlite3_errmsg(db)); return -1; } + if (!has_admitted) { + snprintf(sql, sizeof(sql), "ALTER TABLE \"%s\" ADD COLUMN admitted INTEGER NOT NULL DEFAULT 0", peers_tbl); + if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "member admission schema ch=%s: %s", channel_id, sqlite3_errmsg(db)); return -1; + } + } if (!has_radio_muted) { snprintf(sql, sizeof(sql), "ALTER TABLE \"%s\" ADD COLUMN radio_muted INTEGER NOT NULL DEFAULT 0", peers_tbl); if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK) { @@ -580,6 +589,7 @@ int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id, " deleted INTEGER NOT NULL DEFAULT 0," /* 1 = аккаунт удалён владельцем (не отображаем, не подключаемся) */ " local_nick TEXT," /* локальный ник (GUI only, не синхронизируется) */ " radio_muted INTEGER NOT NULL DEFAULT 0," /* локальное отключение голоса участника */ + " admitted INTEGER NOT NULL DEFAULT 0," /* локальный допуск по текущей политике */ " source INTEGER NOT NULL DEFAULT 0" /* 0=полная merkle-запись 1=упрощённый плейсхолдер topo_group (не участвует в merkle-хеше, дополняется полной записью) */ ")"; @@ -943,7 +953,7 @@ int topo_node_sqlite_member_allowed(sqlite3* db, const char* channel_id, uint64_ DEBUG_WARN(DEBUG_CATEGORY_BGP, "member admission: invalid channel/node"); return 0; } char table[80], sql[256]; peers_table_name(channel_id, table, sizeof(table)); - snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=? AND source=0 AND deleted=0", table); + snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=? AND source=0 AND deleted=0 AND admitted=1", table); sqlite3_stmt* statement = NULL; int rc = sqlite3_prepare_v2(db, sql, -1, &statement, NULL); if (rc == SQLITE_OK) rc = sqlite3_bind_int64(statement, 1, (sqlite3_int64)node_id); @@ -961,7 +971,7 @@ int topo_node_sqlite_member_key_allowed(sqlite3* db, const char* channel_id, con } uint64_t node = sc_derive_node_id_from_pubkey(key); char table[80], sql[320]; peers_table_name(channel_id, table, sizeof(table)); - snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=? AND x25519_pubkey=? AND source=0 AND deleted=0", table); + snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=? AND x25519_pubkey=? AND source=0 AND deleted=0 AND admitted=1", table); sqlite3_stmt* st = NULL; int rc = sqlite3_prepare_v2(db, sql, -1, &st, NULL); if (rc == SQLITE_OK) rc = sqlite3_bind_int64(st, 1, (sqlite3_int64)node); @@ -1634,7 +1644,7 @@ int topo_node_sqlite_get_connect_peers(sqlite3* db, const char* channel_id, char sql[512]; snprintf(sql, sizeof(sql), "SELECT p.node_id,p.adm_tags,s.timestamp,s.record FROM \"%s\" p" - " LEFT JOIN node_snapshots s ON s.node_id=p.node_id AND s.format=1 AND length(s.record)>0 WHERE p.deleted=0 AND p.source=0" + " LEFT JOIN node_snapshots s ON s.node_id=p.node_id AND s.format=1 AND length(s.record)>0 WHERE p.deleted=0 AND p.source=0 AND p.admitted=1" " ORDER BY p.connected DESC,p.node_RTT IS NULL,p.node_RTT,p.node_id", table); sqlite3_stmt* stmt = NULL; int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);