chat: push-invite join key + запрет флагов на плейсхолдере
- CHANNEL_INVITE теперь несёт join_key (регистрируется инвайтером локально), джойнер шлёт JOIN_INFO_REQ с валидным ключом — чинит автоjoin chatserver-узлов - ask-путь сохраняет join_key для chat_sync_accept_invite - chat_member_tags_commit отвергает установку флагов на source!=0 (плейсхолдер) - member_sync_apply_record: defensive ERROR при adm_tags на плейсхолдере
This commit is contained in:
1 parent
0e625da109
commit
b46fd599fa
3 files changed
+63
-8
No files matched your search
@@ -668,7 +668,7 @@ int chat_member_tags_commit(struct UTUN_INSTANCE* inst, struct chat_member_tags*
|
||||
char peers_tbl[80]; peers_table_name(t->ch_id, peers_tbl, sizeof(peers_tbl));
|
||||
sqlite3_stmt* st = NULL;
|
||||
char sql[384]; snprintf(sql, sizeof(sql),
|
||||
"SELECT x25519_pubkey, ed25519_pubkey, join_sig, join_ts, update_sig, update_ts, userinfo, storage"
|
||||
"SELECT x25519_pubkey, ed25519_pubkey, join_sig, join_ts, update_sig, update_ts, userinfo, storage, source"
|
||||
" FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) != SQLITE_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: tags_commit — member query failed", CC_ID); return -1;
|
||||
@@ -685,9 +685,15 @@ int chat_member_tags_commit(struct UTUN_INSTANCE* inst, struct chat_member_tags*
|
||||
uint64_t uts = (uint64_t)sqlite3_column_int64(st, 5);
|
||||
const char* uinfo = (const char*)sqlite3_column_text(st, 6);
|
||||
int stg = sqlite3_column_int(st, 7);
|
||||
int src = sqlite3_column_int(st, 8);
|
||||
if (!x25 || !ed) { sqlite3_finalize(st);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: tags_commit — member has no keys ch=%s", CC_ID, t->ch_id); return -1;
|
||||
}
|
||||
if (src != 0) { sqlite3_finalize(st);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: tags_commit — cannot set flags on placeholder member (source=%d) ch=%s nid=0x%016llx",
|
||||
CC_ID, src, t->ch_id, (unsigned long long)t->node_id);
|
||||
return -1;
|
||||
}
|
||||
const char* stg_val = chat_member_tags_get(t, "storage");
|
||||
if (stg_val && strcmp(stg_val, "yes") == 0) stg = 1;
|
||||
|
||||
|
||||
+50
-6
@@ -31,6 +31,7 @@
|
||||
#include <string.h>
|
||||
#include <sqlite3.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
@@ -76,6 +77,7 @@ struct chat_sync {
|
||||
/* Pending incoming invites (для ask/deny) */
|
||||
uint64_t pending_inv_in_ch_id[4];
|
||||
uint64_t pending_inv_in_node_id[4];
|
||||
uint64_t pending_inv_in_key[4];
|
||||
int pending_inv_in_count;
|
||||
};
|
||||
|
||||
@@ -1403,6 +1405,10 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
||||
/* skip inviter_update_sig/ts/userinfo for now — verify channel sig only */
|
||||
p += 64; uint64_t inviter_update_ts; memcpy(&inviter_update_ts, p, 8); p += 8;
|
||||
uint8_t userinfo_len = *p++; p += userinfo_len;
|
||||
/* join-ключ (зарегистрирован инвайтером) — хвостовые 8 байт */
|
||||
uint64_t join_key = 0;
|
||||
if (p + 8 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE truncated (no join_key) from=%016llx", CS_ID, (unsigned long long)peer); return; }
|
||||
memcpy(&join_key, p, 8); p += 8;
|
||||
|
||||
/* Verify channel signature */
|
||||
uint8_t vmsg[1024]; size_t vlen = 0;
|
||||
@@ -1440,13 +1446,26 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE channel_put rc=%d ch=%s ch_x25519=%016llx",
|
||||
CS_ID, cprc, ch_id, *(const uint64_t*)x25519);
|
||||
chat_core_ensure_channel_ready(cs->inst, ch_id);
|
||||
/* Initiate join: connect back and send CHANNEL_INFO_REQ */
|
||||
/* Initiate join: connect back and send JOIN_INFO_REQ с зарегистрированным ключом */
|
||||
cs->pending_join_key = join_key;
|
||||
chat_sync_join_channel(cs->inst, ch_id, peer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* policy == ask — post event to GUI */
|
||||
{
|
||||
/* сохранить join-ключ, чтобы принять инвайт позже через chat_sync_accept_invite */
|
||||
uint64_t ch_num = strtoull(ch_id, NULL, 10);
|
||||
int slot = -1;
|
||||
for (int i = 0; i < cs->pending_inv_in_count; i++)
|
||||
if (cs->pending_inv_in_ch_id[i] == ch_num && cs->pending_inv_in_node_id[i] == peer) { slot = i; break; }
|
||||
if (slot < 0 && cs->pending_inv_in_count < 4) slot = cs->pending_inv_in_count++;
|
||||
if (slot >= 0) {
|
||||
cs->pending_inv_in_ch_id[slot] = ch_num;
|
||||
cs->pending_inv_in_node_id[slot] = peer;
|
||||
cs->pending_inv_in_key[slot] = join_key;
|
||||
}
|
||||
|
||||
size_t inv_name_len = 0; char inv_name[128] = "";
|
||||
{ sqlite3* vdb = cs->inst->topo_sqlite_db;
|
||||
sqlite3_stmt* st = NULL;
|
||||
@@ -1489,6 +1508,15 @@ static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* in
|
||||
int ulen = member_sync_build_update_msg(join_sig, upd_ts, juser, umsg, (int)sizeof(umsg));
|
||||
if (ulen >= 0) cs_ed25519_sign(inst->my_ed25519_privkey, umsg, (size_t)ulen, upd_sig);
|
||||
}
|
||||
/* join-ключ: генерируем и регистрируем локально (инвайтер == connection-узел),
|
||||
чтобы джойнер смог пройти JOIN_INFO_REQ с валидным ключом. */
|
||||
uint64_t join_key = 0;
|
||||
if (RAND_bytes((uint8_t*)&join_key, sizeof(join_key)) != 1 || join_key == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_key generation failed ch=%s", CS_ID, ch_id);
|
||||
return -1;
|
||||
}
|
||||
chat_join_register_key(inst, strtoull(ch_id, NULL, 10), 0, join_key);
|
||||
|
||||
uint8_t buf[1024]; size_t boff = 0;
|
||||
buf[boff++] = CS_MSG_CHANNEL_INVITE;
|
||||
uint8_t cnl = (uint8_t)strlen(ch_name);
|
||||
@@ -1508,9 +1536,10 @@ static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* in
|
||||
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", inst->name[0] ? inst->name : "");
|
||||
uint8_t il = (uint8_t)strlen(juser);
|
||||
buf[boff++] = il; memcpy(buf + boff, juser, il); boff += il;
|
||||
memcpy(buf + boff, &join_key, 8); boff += 8;
|
||||
int rc = cs_send(cs, ch_id, target_node_id, buf, boff);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s rc=%d",
|
||||
CS_ID, (unsigned long long)target_node_id, ch_id, rc);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s key=%016llx rc=%d",
|
||||
CS_ID, (unsigned long long)target_node_id, ch_id, (unsigned long long)join_key, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1716,16 +1745,31 @@ void chat_sync_invite_to_channel_with_addrs(
|
||||
/* ─── accept/deny incoming invite ─── */
|
||||
|
||||
void chat_sync_accept_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t inviter_node_id) {
|
||||
if (!cs_of(inst) || !inst) return;
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !inst) return;
|
||||
char ch_id[64]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)channel_id);
|
||||
if (channel_id == 0 || inviter_node_id == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite invalid params ch=%llu node=%016llx",
|
||||
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
|
||||
return;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite ch=%llu inviter=0x%016llx",
|
||||
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
|
||||
/* достать join-ключ, сохранённый при приёме CHANNEL_INVITE (ask) */
|
||||
uint64_t join_key = 0;
|
||||
for (int i = 0; i < cs->pending_inv_in_count; i++) {
|
||||
if (cs->pending_inv_in_ch_id[i] == channel_id && cs->pending_inv_in_node_id[i] == inviter_node_id) {
|
||||
join_key = cs->pending_inv_in_key[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (join_key == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite no join_key for ch=%llu inviter=0x%016llx",
|
||||
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
|
||||
return;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite ch=%llu inviter=0x%016llx key=%016llx",
|
||||
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id, (unsigned long long)join_key);
|
||||
chat_core_ensure_channel_ready(inst, ch_id);
|
||||
cs->pending_join_key = join_key;
|
||||
chat_sync_join_channel(inst, ch_id, inviter_node_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,10 +438,11 @@ int member_sync_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
char local_tags[256] = "";
|
||||
uint64_t local_signed_by = 0;
|
||||
uint8_t local_signature[64] = {0};
|
||||
int local_src = 0;
|
||||
{
|
||||
sqlite3_stmt* st = NULL;
|
||||
char sql[512]; snprintf(sql, sizeof(sql),
|
||||
"SELECT join_sig, join_ts, update_ts, adm_tags, signed_by, signature FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
"SELECT join_sig, join_ts, update_ts, adm_tags, signed_by, signature, source FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &st, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)m->node_id);
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
@@ -455,6 +456,7 @@ int member_sync_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
local_signed_by = (uint64_t)sqlite3_column_int64(st, 4);
|
||||
const uint8_t* ls = (const uint8_t*)sqlite3_column_blob(st, 5);
|
||||
if (ls && sqlite3_column_bytes(st, 5) >= 64) memcpy(local_signature, ls, 64);
|
||||
local_src = sqlite3_column_int(st, 6);
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
}
|
||||
@@ -572,6 +574,9 @@ int member_sync_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
if (adm_ver > local_ver) block_b_changed = 1;
|
||||
else if (adm_ver < local_ver) block_b_stale = 1;
|
||||
}
|
||||
if (block_b_changed && local_src != 0)
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: adm_tags change on placeholder member (source=%d) — ignored by merkle, won't propagate nid=0x%016llx ns=%s",
|
||||
MS_ID, local_src, (unsigned long long)m->node_id, ch_id);
|
||||
|
||||
/* ── запись изменённых блоков ── */
|
||||
if (block_a_changed) {
|
||||
|
||||
Reference in new issue
Block a user