diff --git a/src/chat/chat_sync.c b/src/chat/chat_sync.c index e00f5e9c1..1be142193 100644 --- a/src/chat/chat_sync.c +++ b/src/chat/chat_sync.c @@ -1608,11 +1608,32 @@ static void cs_pending_prune(struct chat_sync* cs) { } } +void chat_sync_revalidate_join(struct UTUN_INSTANCE* inst, uint64_t group) { + struct chat_sync* cs = cs_of(inst); + if (!cs || !cs->initialized) return; + struct join_pending** link = &cs->join_pending; + while (*link) { + struct join_pending* p = *link; + uint64_t channel = strtoull(p->ch_id, NULL, 10); + if ((group && group != channel) || (topo_group_chat_allowed(inst, channel, p->inviter) && + group_policy_can_invite(inst, p->ch_id, p->inviter) == 1)) { link = &p->next; continue; } + *link = p->next; + DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "join waiter revoked ch=%s peer=%016llx inviter=%016llx attempt=%016llx", p->ch_id, + (unsigned long long)p->node_id, (unsigned long long)p->inviter, (unsigned long long)p->attempt); + int32_t code = CHAT_CONNECT_AUTH; + uint8_t error[5] = {CS_MSG_ERROR}; memcpy(error + 1, &code, 4); + cs_send_attempt(cs, p->ch_id, p->node_id, error, sizeof(error), p->attempt, &p->route); + if (p->route.handle && inst->join_carrier) inst->join_carrier->close(inst->join_carrier->ctx, p->route.handle, 0); + u_free(p); + } +} + /* ─── отправка JOIN_READY джойнеру + снятие pending (connection-узел) ─── */ static void cs_send_join_ready(struct chat_sync* cs, const char* ch_id, uint64_t node_id) { - if (!topo_node_sqlite_member_allowed(cs->inst->topo_sqlite_db, ch_id, node_id)) return; uint64_t group = strtoull(ch_id, NULL, 10); + chat_sync_revalidate_join(cs->inst, group); + if (!topo_group_chat_allowed(cs->inst, group, node_id)) return; uint8_t data[9] = { CS_MSG_JOIN_READY }; memcpy(data + 1, &group, 8); int sent = 0; struct join_pending** link = &cs->join_pending; @@ -1644,6 +1665,7 @@ void chat_sync_join_inviter_result(struct UTUN_INSTANCE* inst, uint64_t channel, uint64_t attempt, uint64_t node, int result) { struct chat_sync* cs = cs_of(inst); if (!cs || !cs->initialized) return; + chat_sync_revalidate_join(inst, channel); char ch[32]; snprintf(ch, sizeof(ch), "%llu", (unsigned long long)channel); struct join_pending** link = &cs->join_pending; while (*link) { diff --git a/src/chat/chat_sync.h b/src/chat/chat_sync.h index 8913a04cd..8af2f5d66 100644 --- a/src/chat/chat_sync.h +++ b/src/chat/chat_sync.h @@ -103,6 +103,9 @@ void chat_sync_join_result(struct UTUN_INSTANCE* inst, uint64_t request, uint64_ /* Подписанный ответ инвайтера на forwarded JOIN. Проверяет inviter, attempt и node ожидающего запроса. */ void chat_sync_join_inviter_result(struct UTUN_INSTANCE* inst, uint64_t channel, uint64_t inviter, uint64_t attempt, uint64_t node, int result); +/* uasync после commit: отменить ожидания JOIN_READY, если connection/инвайтер потеряли доступ или право приглашать. + * group=0 проверяет все каналы. Джойнеру членство до сохранения его записи не требуется. */ +void chat_sync_revalidate_join(struct UTUN_INSTANCE* inst, uint64_t group); /* uasync: пригласить адресата в свой channel. SERVER-ссылка запускает запрос с add_key и обычным * приглашением через self; успех возвращает сервер после своего JOIN. CHANNEL — обычный push-invite. diff --git a/src/routing_layer/topo_group.c b/src/routing_layer/topo_group.c index 626ef437f..313a9a892 100644 --- a/src/routing_layer/topo_group.c +++ b/src/routing_layer/topo_group.c @@ -34,6 +34,8 @@ #include "../stream/stream.h" #include "../chat/chat_setting.h" #include "../chat/group_avatar.h" +#include "../chat/chat_join.h" +#include "../chat/chat_sync.h" #include "../member_files/member_files.h" #define TOPO_GROUP_UTUN 0x8000000000000000ULL @@ -446,6 +448,8 @@ void topo_group_revalidate_members(struct TOPO_GROUP* group) { radio_call_revalidate_members(group->instance, group->group_id); member_files_revalidate_members(group->instance, group->group_id); group_avatar_revalidate_members(group->instance, group->group_id); + chat_join_revalidate_members(group->instance, group->group_id); + chat_sync_revalidate_join(group->instance, group->group_id); /* Удаление вызывает callbacks и меняет список; каждый раз ищем следующего заново. */ for (;;) { struct TOPO_GROUP_CONN_ITEM* invalid = NULL;