Restrict feedback invalidation to credential, key and admission changes
This commit is contained in:
1 parent
5cae3d095d
commit
953e094c92
3 files changed
+44
-18
No files matched your search
@@ -1276,7 +1276,7 @@ static void cs_handle_join_info_resp(struct chat_sync* cs, uint64_t peer,
|
||||
}
|
||||
if (cs->info_req_timer) { uasync_cancel_timeout(cs->inst->ua, cs->info_req_timer); cs->info_req_timer = NULL; }
|
||||
if (chat_core_ensure_channel_ready(cs->inst, ch_id) < 0) { cs_join_finish(cs, CHAT_CONNECT_ERROR); return; }
|
||||
member_sync_record_committed(cs->inst, ch_id, c_node_id);
|
||||
member_sync_record_committed(cs->inst, ch_id, c_node_id, (unsigned)mrc);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "join channel committed ch=%s member=%016llx", ch_id, (unsigned long long)c_node_id);
|
||||
|
||||
/* построить собственный join_sig */
|
||||
|
||||
+40
-16
@@ -508,7 +508,7 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
return -1;
|
||||
}
|
||||
sqlite3* db = _db(inst); if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_record — db is NULL", MS_ID); return -1; }
|
||||
int stale = 0, changed = 0;
|
||||
int stale = 0, changed = 0, node_key_changed = 0;
|
||||
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_record ch=%s nid=%016llx uts=%llu tags_bytes=%zu",
|
||||
MS_ID, ch_id, (unsigned long long)m->node_id, (unsigned long long)m->update_ts,
|
||||
@@ -523,11 +523,12 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
char local_tags[MS_ADM_TAGS_MAX + 1] = "";
|
||||
uint64_t local_signed_by = 0;
|
||||
uint8_t local_signature[64] = {0};
|
||||
int local_src = 0;
|
||||
int local_src = 0, local_identity_matches = 0, local_deleted = 0;
|
||||
{
|
||||
sqlite3_stmt* st = NULL;
|
||||
char sql[512]; snprintf(sql, sizeof(sql),
|
||||
"SELECT join_sig, join_ts, update_ts, adm_tags, signed_by, signature, source FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
"SELECT join_sig,join_ts,update_ts,adm_tags,signed_by,signature,source,x25519_pubkey,ed25519_pubkey,deleted"
|
||||
" FROM \"%s\" WHERE node_id=?", peers_tbl);
|
||||
int rc = sqlite3_prepare_v2(db, sql, -1, &st, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_int64(st, 1, (sqlite3_int64)m->node_id);
|
||||
if (rc == SQLITE_OK) {
|
||||
@@ -545,6 +546,11 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
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);
|
||||
const void* old_x = sqlite3_column_blob(st, 7); const void* old_ed = sqlite3_column_blob(st, 8);
|
||||
local_identity_matches = old_x && old_ed && sqlite3_column_bytes(st, 7) == 32 && sqlite3_column_bytes(st, 8) == 32
|
||||
&& !memcmp(old_x, m->x25519, 32) && !memcmp(old_ed, m->ed25519, 32);
|
||||
local_deleted = sqlite3_column_int(st, 9);
|
||||
if (sqlite3_errcode(db) == SQLITE_NOMEM) rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
@@ -699,6 +705,12 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
/* узел в nodes пишет только merkle-путь (verified identity) */
|
||||
char node_name[128] = "";
|
||||
if (m->userinfo) json_flat_get(m->userinfo, "name", node_name, sizeof(node_name));
|
||||
if (merkle_sync_registered(inst, MT_DATA_FEEDBACK)) {
|
||||
uint8_t previous_key[32];
|
||||
int lookup = topo_node_sqlite_get_ed25519_pubkey(db, m->node_id, previous_key);
|
||||
if (lookup == TOPO_SQLITE_LOOKUP_ERROR) return MT_ERR_IO;
|
||||
node_key_changed = lookup == TOPO_SQLITE_LOOKUP_MISSING || memcmp(previous_key, m->ed25519, 32);
|
||||
}
|
||||
if (topo_node_sqlite_node_update_verified(db, m->node_id, node_name, m->x25519, m->ed25519,
|
||||
m->update_ts ? m->update_ts : m->join_ts,
|
||||
ntp_time_get_seconds(inst)) < 0) {
|
||||
@@ -739,23 +751,32 @@ static int member_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
(unsigned long long)m->node_id); return MT_ERR_IO;
|
||||
}
|
||||
|
||||
char deleted_value[16];
|
||||
int deleted_changed = block_b_changed && local_deleted != (json_flat_get(m->adm_tags, "deleted",
|
||||
deleted_value, sizeof(deleted_value)) == 0 && !strcmp(deleted_value, "yes"));
|
||||
int credentials_changed = block_a_changed && (!has_local || local_src != 0 || !local_identity_matches
|
||||
|| m->join_ts != local_join_ts || (m->join_sig && memcmp(m->join_sig, local_join_sig, 64))
|
||||
|| (has_signature && (m->signed_by != local_signed_by || memcmp(m->signature, local_signature, 64))));
|
||||
int feedback_changed = merkle_sync_registered(inst, MT_DATA_FEEDBACK)
|
||||
&& (credentials_changed || signature_changed || deleted_changed || node_key_changed);
|
||||
|
||||
/* Профиль/stream options не меняют допуск feedback и не требуют новых его раундов. */
|
||||
if (feedback_changed && chat_feedback_member_update(inst, m->node_id) < 0) return MT_ERR_IO;
|
||||
/* ── recompute и подтвердить реальное изменение по хешу ── */
|
||||
if (changed) {
|
||||
/* Общий ключ может разрешить удостоверения приглашённых в других каналах. */
|
||||
if (chat_feedback_member_update(inst, m->node_id) < 0) return MT_ERR_IO;
|
||||
int rc = merkle_sync_recompute_path(inst, MT_DATA_MEMBERS, ch_id, m->node_id);
|
||||
if (rc < 0) return -1;
|
||||
if (rc == 0) changed = 0; /* запись была no-op (данные идентичны) */
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_record ch=%s nid=0x%016llx → changed=%d stale=%d",
|
||||
MS_ID, ch_id, (unsigned long long)m->node_id, changed, stale);
|
||||
return (changed ? MS_APPLY_CHANGED : 0) | (stale ? MS_APPLY_STALE : 0);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_record ch=%s nid=0x%016llx → changed=%d stale=%d feedback=%d",
|
||||
MS_ID, ch_id, (unsigned long long)m->node_id, changed, stale, feedback_changed);
|
||||
return (changed ? MS_APPLY_CHANGED : 0) | (stale ? MS_APPLY_STALE : 0) | (feedback_changed ? MS_APPLY_FEEDBACK : 0);
|
||||
}
|
||||
|
||||
void member_sync_record_committed(struct UTUN_INSTANCE* inst, const char* ns, uint64_t node_id) {
|
||||
void member_sync_record_committed(struct UTUN_INSTANCE* inst, const char* ns, uint64_t node_id, unsigned changes) {
|
||||
merkle_sync_changed(inst, MT_DATA_MEMBERS, ns);
|
||||
chat_feedback_member_committed(inst, node_id);
|
||||
if (changes & MS_APPLY_FEEDBACK) chat_feedback_member_committed(inst, node_id);
|
||||
struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)) : NULL;
|
||||
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
|
||||
if (g && g->group_type == TOPO_GROUP_TYPE_CHAT) {
|
||||
@@ -785,7 +806,8 @@ int member_sync_apply_record(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: record cleanup: %s", MS_ID, sqlite3_errmsg(db));
|
||||
return -1;
|
||||
}
|
||||
if (own && rc >= 0 && (rc & MS_APPLY_CHANGED)) member_sync_record_committed(inst, ch_id, m->node_id);
|
||||
if (own && rc >= 0 && (rc & (MS_APPLY_CHANGED | MS_APPLY_FEEDBACK)))
|
||||
member_sync_record_committed(inst, ch_id, m->node_id, (unsigned)rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1089,7 +1111,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer, co
|
||||
w.rec.join_sig = w.local_join;
|
||||
int r = member_sync_apply_record(inst, ns, from_peer, &w.rec);
|
||||
if (r < 0) { rc = r; break; }
|
||||
changed[i] = (r & MS_APPLY_CHANGED) != 0;
|
||||
changed[i] = r & (MS_APPLY_CHANGED | MS_APPLY_FEEDBACK);
|
||||
off += used;
|
||||
}
|
||||
if (rc < 0 && sqlite3_exec(db, "ROLLBACK TO member_page", NULL, NULL, NULL) != SQLITE_OK)
|
||||
@@ -1105,10 +1127,12 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer, co
|
||||
struct member_wire w; size_t used;
|
||||
if (member_decode(data + off, len - off, &w, &used) < 0) { rc = MT_ERR_DATA; break; }
|
||||
if (changed[i]) {
|
||||
member_sync_record_committed(inst, ns, w.rec.node_id);
|
||||
if (!inst->topo_groups || !topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)))
|
||||
_fire_props_changed(inst, w.rec.node_id, w.tags[0] ? w.tags : NULL, ns);
|
||||
_fire_apply_cbk(inst, ns, w.rec.node_id, w.rec.x25519, w.rec.signed_by, w.rec.signature);
|
||||
member_sync_record_committed(inst, ns, w.rec.node_id, changed[i]);
|
||||
if (changed[i] & MS_APPLY_CHANGED) {
|
||||
if (!inst->topo_groups || !topo_groups_find(inst->topo_groups, strtoull(ns, NULL, 10)))
|
||||
_fire_props_changed(inst, w.rec.node_id, w.tags[0] ? w.tags : NULL, ns);
|
||||
_fire_apply_cbk(inst, ns, w.rec.node_id, w.rec.x25519, w.rec.signed_by, w.rec.signature);
|
||||
}
|
||||
}
|
||||
off += used;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ int member_sync_verified_ed25519(struct UTUN_INSTANCE* inst, const char* channel
|
||||
/* Результат применения рекорда мембера (compare+update по версиям двух блоков). */
|
||||
#define MS_APPLY_CHANGED 0x01 /* запись и дерево обновлены */
|
||||
#define MS_APPLY_STALE 0x02 /* локальная версия новее; обратный проход доставит её пиру */
|
||||
#define MS_APPLY_FEEDBACK 0x04 /* изменилось удостоверение, доверенный ключ или deleted; индекс feedback обновлён */
|
||||
#define MS_VERIFY_DEFERRED (-1) /* зависимость подписи ещё не получена */
|
||||
#define MS_VERIFY_ERROR (-2) /* SQL/crypto/аргументы: проверка не выполнена */
|
||||
|
||||
@@ -250,8 +251,9 @@ int member_sync_add_props_cbk(struct UTUN_INSTANCE* inst, node_props_changed_fn
|
||||
void member_sync_remove_props_cbk(struct UTUN_INSTANCE* inst, node_props_changed_fn fn, void* arg);
|
||||
|
||||
/* После внешнего commit уведомить Merkle, свойства и планировщик CHAT-группы.
|
||||
* changes — полная маска MS_APPLY_* из apply_record/put: FEEDBACK разрешает его уведомления.
|
||||
* inst/channel обязательны; uasync, БД уже вне транзакции. Не вызывает apply callbacks. */
|
||||
void member_sync_record_committed(struct UTUN_INSTANCE* inst, const char* channel, uint64_t node_id);
|
||||
void member_sync_record_committed(struct UTUN_INSTANCE* inst, const char* channel, uint64_t node_id, unsigned changes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user