chat_join: модуль join-протокола, invite-ссылки v2, синхронизация мемберов

This commit is contained in:
evgeny committed 2026-09-14 19:57:27 +03:00
1 parent a01a4ddba4
commit 75e39d2fee
41 files changed
+2206 -471

No files matched your search

+44 -4
View File
@@ -351,6 +351,8 @@ int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
" update_ts INTEGER DEFAULT 0," /* NTP timestamp подписи update_sig */
" userinfo TEXT NOT NULL DEFAULT ''," /* JSON с информацией о пользователе: {"name":"<display_name>"} */
" creator_sig BLOB," /* Ed25519 подпись создателя (PEERS_JOIN_SIG_SIZE=64), пока заглушка */
" signed_by INTEGER," /* node_id инвайтера (родитель в дереве приглашений); 0 = корень, подписан ключом группы */
" signature BLOB," /* Ed25519 подпись x25519_pubkey||"group_join" ключом родителя (или канальным ed25519 для корня) */
" adm_tags TEXT," /* JSON-теги администратора: {"key":"val",...,"ver":"N"}.
подпись: sc_ed25519_sign(ch_ed_priv, json||node_id_8LE) */
" adm_tags_sig BLOB," /* Ed25519 подпись над adm_tags (64 байта) канальным ключом */
@@ -480,14 +482,15 @@ int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint6
const uint8_t* join_sig, uint64_t join_ts,
const uint8_t* update_sig, uint64_t update_ts,
const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey,
const char* userinfo, const uint8_t* creator_sig) {
const char* userinfo, const uint8_t* creator_sig,
uint64_t signed_by, const uint8_t* signature) {
if (!db || !channel_id || !x25519_pubkey || !ed25519_pubkey) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[640];
char sql[768];
snprintf(sql, sizeof(sql),
"INSERT INTO \"%s\"(node_id, x25519_pubkey, ed25519_pubkey,"
" join_sig, join_ts, update_sig, update_ts, userinfo, creator_sig)"
" VALUES(?,?,?,?,?,?,?,?,?)"
" join_sig, join_ts, update_sig, update_ts, userinfo, creator_sig, signed_by, signature)"
" VALUES(?,?,?,?,?,?,?,?,?,?,?)"
" ON CONFLICT(node_id) DO UPDATE SET"
" x25519_pubkey=excluded.x25519_pubkey,"
" ed25519_pubkey=excluded.ed25519_pubkey,"
@@ -497,6 +500,8 @@ int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint6
" update_ts=excluded.update_ts,"
" userinfo=excluded.userinfo,"
" creator_sig=excluded.creator_sig,"
" signed_by=excluded.signed_by,"
" signature=excluded.signature,"
" source=0", peers_tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
@@ -512,6 +517,9 @@ int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint6
sqlite3_bind_text(stmt, 8, userinfo ? userinfo : "", -1, SQLITE_STATIC);
if (creator_sig) sqlite3_bind_blob(stmt, 9, creator_sig, PEERS_JOIN_SIG_SIZE, SQLITE_STATIC);
else sqlite3_bind_null(stmt, 9);
sqlite3_bind_int64(stmt, 10, (sqlite3_int64)signed_by);
if (signature) sqlite3_bind_blob(stmt, 11, signature, 64, SQLITE_STATIC);
else sqlite3_bind_null(stmt, 11);
int rc = sqlite3_step(stmt); sqlite3_finalize(stmt);
return rc == SQLITE_DONE ? 0 : -1;
}
@@ -583,6 +591,38 @@ int topo_node_sqlite_member_get_join(sqlite3* db, const char* channel_id, uint64
return rc;
}
int topo_node_sqlite_member_get_sign(sqlite3* db, const char* channel_id, uint64_t node_id,
uint64_t* signed_by_out, uint8_t signature_out[64]) {
if (!db || !channel_id || !signed_by_out || !signature_out) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[256];
snprintf(sql, sizeof(sql), "SELECT signed_by, signature FROM \"%s\" WHERE node_id=?", peers_tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
int rc = -1;
if (sqlite3_step(stmt) == SQLITE_ROW) {
*signed_by_out = (uint64_t)sqlite3_column_int64(stmt, 0);
const uint8_t* sig = (const uint8_t*)sqlite3_column_blob(stmt, 1);
if (sig && sqlite3_column_bytes(stmt, 1) >= 64) { memcpy(signature_out, sig, 64); rc = 0; }
}
sqlite3_finalize(stmt);
return rc;
}
int topo_node_sqlite_member_in_channel(sqlite3* db, const char* channel_id, uint64_t node_id) {
if (!db || !channel_id || node_id == 0) return 0;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[256];
snprintf(sql, sizeof(sql), "SELECT 1 FROM \"%s\" WHERE node_id=?", peers_tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return 0;
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
int found = (sqlite3_step(stmt) == SQLITE_ROW);
sqlite3_finalize(stmt);
return found;
}
int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t node_id) {
if (!db || !channel_id) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
+10 -2
View File
@@ -41,12 +41,20 @@ int topo_node_sqlite_channel_delete(sqlite3* db, const char* channel_id);
int topo_node_sqlite_member_placeholder_put(sqlite3* db, const char* channel_id, uint64_t node_id,
const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey);
/* Обновляет только блок мембера (keys/join/update_sig/update_ts/userinfo), не трогая блок владельца. */
/* Обновляет только блок мембера (keys/join/update_sig/update_ts/userinfo), не трогая блок владельца.
* signed_by/signature — дерево приглашений: кто подписал pubkey узла (0 = корень, ключом группы). */
int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint64_t node_id,
const uint8_t* join_sig, uint64_t join_ts,
const uint8_t* update_sig, uint64_t update_ts,
const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey, const char* userinfo,
const uint8_t* creator_sig);
const uint8_t* creator_sig, uint64_t signed_by, const uint8_t* signature);
/* Прочитать дерево приглашений мембера (signed_by + signature). 0=ок, -1=нет записи/полей. */
int topo_node_sqlite_member_get_sign(sqlite3* db, const char* channel_id, uint64_t node_id,
uint64_t* signed_by_out, uint8_t signature_out[64]);
/* Есть ли узел в таблице мемберов канала peers_<ch_id> (source 0 или 1). 1=да, 0=нет. */
int topo_node_sqlite_member_in_channel(sqlite3* db, const char* channel_id, uint64_t node_id);
/* Обновляет только блок владельца (adm_tags/adm_tags_sig/storage). */
int topo_node_sqlite_member_owner_put(sqlite3* db, const char* channel_id, uint64_t node_id,