diff --git a/src/chat/chat_sync.c b/src/chat/chat_sync.c index 043084877..a4c3f9537 100644 --- a/src/chat/chat_sync.c +++ b/src/chat/chat_sync.c @@ -1600,6 +1600,7 @@ static void cs_send_join_ready(struct chat_sync* cs, const char* ch_id, uint64_t if (!topo_node_sqlite_member_allowed(cs->inst->topo_sqlite_db, ch_id, node_id)) return; uint64_t group = strtoull(ch_id, NULL, 10); uint8_t data[9] = { CS_MSG_JOIN_READY }; memcpy(data + 1, &group, 8); + int sent = 0; struct join_pending** link = &cs->join_pending; while (*link) { struct join_pending* pending = *link; @@ -1620,8 +1621,9 @@ static void cs_send_join_ready(struct chat_sync* cs, const char* ch_id, uint64_t DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "join ready peer=%016llx attempt=%016llx", (unsigned long long)node_id, (unsigned long long)pending->attempt); *link = pending->next; u_free(pending); + sent++; } - cs_schedule_sync(cs, group, node_id, "join_accepted"); + if (sent) cs_schedule_sync(cs, group, node_id, "join_accepted"); } void chat_sync_join_rejected(struct UTUN_INSTANCE* inst, uint64_t channel, uint64_t inviter, diff --git a/tests/test_chat_join.c b/tests/test_chat_join.c index 52c644e5f..354cd2de5 100644 --- a/tests/test_chat_join.c +++ b/tests/test_chat_join.c @@ -158,11 +158,11 @@ static int serialize_member(uint64_t node_id, const uint8_t* x25519, const uint8 /* ── 5.1.1 build_sign_msg ── */ static void t_build_sign_msg(void) { - TEST("member_sync_build_sign_msg: 42 bytes"); { - uint8_t x[32], priv[32], out[64]; gen_x25519(x, priv); + TEST("member_sync_build_sign_msg: 74 bytes"); { + uint8_t x[64] = {1}, out[74]; int n = member_sync_build_sign_msg(x, out, (int)sizeof(out)); - if (n == MEMBER_SIGN_MSG_SIZE && memcmp(out, x, 32) == 0 - && memcmp(out + 32, MEMBER_SIGN_SUFFIX, MEMBER_SIGN_SUFFIX_LEN) == 0) OK(); + if (n == MEMBER_SIGN_MSG_SIZE && memcmp(out, x, 64) == 0 + && memcmp(out + 64, MEMBER_SIGN_SUFFIX, MEMBER_SIGN_SUFFIX_LEN) == 0) OK(); else FAIL("n=%d", n); } TEST("member_sync_build_sign_msg: short buffer -> -1"); { @@ -193,35 +193,35 @@ static void t_sign_verify(void) { (uint64_t)time(NULL), time(NULL)); struct ms_member_rec rec; - uint8_t sig[64]; + uint8_t sig[64], join[64] = {1}, other_join[64] = {2}; TEST("verify_signature: root (signed_by=0, channel ed25519) == 1"); { - member_sync_sign_pubkey(ch_ed_priv, jx, sig); - memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.signature = sig; rec.signed_by = 0; + member_sync_sign_join(ch_ed_priv, join, sig); + memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.join_sig = join; rec.signature = sig; rec.signed_by = 0; if (member_sync_verify_signature(db, CH_COMP, &rec) == 1) OK(); else FAIL(); } TEST("verify_signature: child (signed_by=parent) == 1"); { - member_sync_sign_pubkey(p_ed_priv, jx, sig); - memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.signature = sig; rec.signed_by = parent_id; + member_sync_sign_join(p_ed_priv, join, sig); + memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.join_sig = join; rec.signature = sig; rec.signed_by = parent_id; if (member_sync_verify_signature(db, CH_COMP, &rec) == 1) OK(); else FAIL(); } - TEST("verify_signature: tampered x25519 == 0"); { - member_sync_sign_pubkey(ch_ed_priv, jx, sig); - memset(&rec, 0, sizeof(rec)); rec.x25519 = other_x; rec.signature = sig; rec.signed_by = 0; + TEST("verify_signature: tampered join_sig == 0"); { + member_sync_sign_join(ch_ed_priv, join, sig); + memset(&rec, 0, sizeof(rec)); rec.x25519 = other_x; rec.join_sig = other_join; rec.signature = sig; rec.signed_by = 0; if (member_sync_verify_signature(db, CH_COMP, &rec) == 0) OK(); else FAIL(); } TEST("verify_signature: parent not in nodes == -1"); { - member_sync_sign_pubkey(ch_ed_priv, jx, sig); - memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.signature = sig; rec.signed_by = 0x7777ULL; + member_sync_sign_join(ch_ed_priv, join, sig); + memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.join_sig = join; rec.signature = sig; rec.signed_by = 0x7777ULL; if (member_sync_verify_signature(db, CH_COMP, &rec) == -1) OK(); else FAIL(); } TEST("verify_signature: no channel == -1"); { - member_sync_sign_pubkey(ch_ed_priv, jx, sig); - memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.signature = sig; rec.signed_by = 0; + member_sync_sign_join(ch_ed_priv, join, sig); + memset(&rec, 0, sizeof(rec)); rec.x25519 = jx; rec.join_sig = join; rec.signature = sig; rec.signed_by = 0; if (member_sync_verify_signature(db, "99999999999", &rec) == -1) OK(); else FAIL(); } @@ -657,7 +657,7 @@ static void t_registration_edges(void) { struct chat_join_registration* req = chat_join_register_key(g_inst[0], g_group_id, g_nid[1], JOIN_KEY + 26, registered, &r); uint8_t key[32] = {0}; struct join_member_data member = {0}; member.node_id = g_nid[0]; member.x25519 = member.ed25519 = key; - int forwarded = chat_join_forward_request(g_inst[0], g_group_id, g_nid[1], JOIN_KEY, &member); + int forwarded = chat_join_forward_request(g_inst[0], g_group_id, g_nid[1], JOIN_KEY, 1, &member); g_inst[0]->router_conns = saved; timeout_heap_peek(g_ua->timeout_heap, &timer); /* освобождает отменённые таймеры без вызова callback */ if (!req && !r.calls && forwarded == -1 && !g_inst[0]->join_registrations diff --git a/tests/test_chat_sync_schedule.c b/tests/test_chat_sync_schedule.c index 70058b140..b9ff60b80 100644 --- a/tests/test_chat_sync_schedule.c +++ b/tests/test_chat_sync_schedule.c @@ -106,6 +106,8 @@ static void setup(struct fixture* f) { if ((i == 0 && ch == 1) || (i == 2 && ch == 0)) continue; assert(topo_node_sqlite_member_block_put(f->inst->topo_sqlite_db, f->channel[ch], conn->peer_node_id, signature, 1, signature, 1, keys.public_key, keys.public_key, "{}", NULL, 0, signature) == 0); + char sql[128]; snprintf(sql, sizeof(sql), "UPDATE peers_%s SET admitted=1", f->channel[ch]); + assert(sqlite3_exec(f->inst->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK); } } /* Кеш намеренно не обновляем: задания должны видеть актуальное членство в БД. */ @@ -177,7 +179,9 @@ static void test_join_existing_transport(void) { struct fixture f; setup(&f); struct chat_join_route route = {.peer = f.peers[0]->peer_node_id}; memcpy(route.public_key, f.peers[0]->crypto_ctx.peer_public_key, sizeof(route.public_key)); - assert(cs_pending_add(f.inst->chat_sync, f.peers[0]->peer_node_id, f.channel[0], &route, 1) == 0); + uint8_t join[64] = {0}; struct join_member_data member = {.join_ts = 1, .join_sig = join}; + assert(cs_pending_add(f.inst->chat_sync, f.peers[0]->peer_node_id, f.channel[0], &route, 1, f.inst->node_id, &member) == 0); + f.inst->chat_sync->join_pending->confirmed = 1; cs_send_join_ready(f.inst->chat_sync, f.channel[0], f.peers[0]->peer_node_id); assert(!start_count); run_ms(&f, 1100); assert(start_count == 1 && starts[0].peer == f.peers[0]->peer_node_id && starts[0].channel == f.gid[0]);