diff --git a/tests/test_chat_feedback.c b/tests/test_chat_feedback.c index 9e87fffc..464bb94f 100644 --- a/tests/test_chat_feedback.c +++ b/tests/test_chat_feedback.c @@ -51,8 +51,47 @@ static void sign_record(const struct UTUN_INSTANCE* author, uint64_t channel, st assert(sc_ed25519_sign(author->my_ed25519_privkey, body, bytes, r->signature) == SC_OK); } -int main(void) { +static void check_author_rejection(struct UTUN_INSTANCE* inst) { + sqlite3_stmt* st = NULL; uint8_t key[32], tree[64]; + assert(member_sync_sign_pubkey(owner_private, inst->my_keys.public_key, tree) == 0); + assert(fb_author_key(inst, "1001", inst->node_id, key) == 0 && !memcmp(key, inst->my_ed25519_pubkey, 32)); + assert(sqlite3_prepare_v2(inst->topo_sqlite_db, "UPDATE peers_1001 SET signature=? WHERE node_id=?", -1, &st, NULL) == SQLITE_OK); + uint8_t zero[64] = {0}; sqlite3_bind_blob(st, 1, zero, 64, SQLITE_STATIC); sqlite3_bind_int64(st, 2, inst->node_id); + assert(sqlite3_step(st) == SQLITE_DONE && fb_author_key(inst, "1001", inst->node_id, key) < 0); + sqlite3_reset(st); sqlite3_bind_null(st, 1); + assert(sqlite3_step(st) == SQLITE_DONE && fb_author_key(inst, "1001", inst->node_id, key) < 0); + sqlite3_reset(st); tree[0] ^= 1; sqlite3_bind_blob(st, 1, tree, 64, SQLITE_STATIC); + assert(sqlite3_step(st) == SQLITE_DONE && fb_author_key(inst, "1001", inst->node_id, key) < 0); + sqlite3_reset(st); tree[0] ^= 1; + assert(sqlite3_step(st) == SQLITE_DONE && fb_author_key(inst, "1001", inst->node_id, key) == 0); + sqlite3_finalize(st); + puts("PASS: root author requires a valid channel signature; zero, missing and forged certificates are rejected"); +} + +/* Диагностика копии профиля: без изменения записей или доступа к приватным ключам. */ +static int check_profile_authors(const char* path) { + struct UTUN_INSTANCE inst = {0}; + assert(sqlite3_open_v2(path, &inst.topo_sqlite_db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK); + sqlite3_stmt *channels = NULL, *members = NULL; + assert(sqlite3_prepare_v2(inst.topo_sqlite_db, "SELECT channel_id FROM channels", -1, &channels, NULL) == SQLITE_OK); + int total = 0, rc; + while ((rc = sqlite3_step(channels)) == SQLITE_ROW) { + const char* channel = (const char*)sqlite3_column_text(channels, 0); char sql[256]; + snprintf(sql, sizeof(sql), "SELECT node_id FROM peers_%s WHERE source=0", channel); + assert(sqlite3_prepare_v2(inst.topo_sqlite_db, sql, -1, &members, NULL) == SQLITE_OK); + int step; + while ((step = sqlite3_step(members)) == SQLITE_ROW) { + uint8_t key[32]; assert(fb_author_key(&inst, channel, sqlite3_column_int64(members, 0), key) == 0); total++; + } + assert(step == SQLITE_DONE); sqlite3_finalize(members); members = NULL; + } + assert(rc == SQLITE_DONE); sqlite3_finalize(channels); assert(sqlite3_close(inst.topo_sqlite_db) == SQLITE_OK); + printf("PASS: all %d authors in the profile have valid node keys, joins and invitation certificates\n", total); return 0; +} + +int main(int argc, char** argv) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); + if (argc == 2) return check_profile_authors(argv[1]); size_t baseline = u_get_allocated_count(); struct UASYNC* ua = uasync_create(); assert(ua); struct UTUN_INSTANCE source, target; setup(&source, ua); setup(&target, ua); @@ -61,6 +100,7 @@ int main(void) { add_member(&source, &source, channel); add_member(&target, &source, channel); add_member(&source, &target, channel); add_member(&target, &target, channel); } + check_author_rejection(&source); uint8_t message[32], other_message[32], signature[64] = {7}; assert(chat_message_id(1001, 123, signature, message) == 0); assert(chat_message_id(1002, 123, signature, other_message) == 0 && memcmp(message, other_message, 32));