Reproduce revoked history and sound access on shared transport
This commit is contained in:
1 parent
f4939e4444
commit
c11e38963a
1 file changed
+98
-1
@@ -11,6 +11,7 @@
|
||||
#include "chat/member_sync.h"
|
||||
#include "chat/chat_event.h"
|
||||
#include "chat/chat_join.h"
|
||||
#include "chat/chat_sync.h"
|
||||
#include "chat/chat_core_priv.h"
|
||||
#include "chat/chat_attachment.h"
|
||||
#include "media_async/media_async.h"
|
||||
@@ -38,6 +39,9 @@
|
||||
#include "../src/routing_layer/multicast.c"
|
||||
/* Сверяем активные операции/offset после сетевой инъекции и до файловых callbacks. */
|
||||
#include "../src/media_delivery/file_transfer.c"
|
||||
/* Сверяем историю, настройки и отложенную выдачу настоящих моделей синхронизации. */
|
||||
#include "../src/chat/db_sync.c"
|
||||
#include "../src/chat/merkle_sync.c"
|
||||
|
||||
#define REQUIRE(expr) do { if (!(expr)) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "isolation setup: %s", #expr); return -1; } } while (0)
|
||||
|
||||
@@ -959,6 +963,98 @@ static int dm_isolation(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* READY намеренно остаётся прежним: отзыв проверяется до уведомлений BGP и на границе выдачи. */
|
||||
static int history_isolation(void) {
|
||||
struct UTUN_INSTANCE* server = fixture.nodes[0]; struct UTUN_INSTANCE* client = fixture.nodes[1];
|
||||
struct ETCP_CONN* conn = instance_find_conn(server, client->node_id);
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, "UPDATE peers_112 SET admitted=1", NULL, NULL, NULL) == SQLITE_OK);
|
||||
member_sync_destroy(server); /* chat_sync владеет новым общим Merkle вместо отдельного тестового MEMBERS. */
|
||||
REQUIRE(!chat_sync_init(server));
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
REQUIRE(!topo_group_new_conn(fixture.groups[i][1], instance_find_conn(fixture.nodes[i], fixture.nodes[1 - i]->node_id)));
|
||||
uint64_t deadline = get_time_tb() + 50000;
|
||||
while (!topo_group_peer_ready(fixture.groups[0][1], client->node_id) && get_time_tb() < deadline) uasync_poll(fixture.ua, 1);
|
||||
REQUIRE(topo_group_peer_ready(fixture.groups[0][1], client->node_id));
|
||||
for (unsigned i = 0; i < 100; i++) uasync_poll(fixture.ua, 1);
|
||||
const uint8_t services[] = {ETCP_ID_DB_SYNC, ETCP_ID_CHAT_SYNC, ETCP_ID_MEMBER_SYNC};
|
||||
for (unsigned i = 0; i < sizeof(services); i++) {
|
||||
fixture.receivers[services[i]] = server->api_bindings.callbacks[services[i]];
|
||||
REQUIRE(fixture.receivers[services[i]]); server->api_bindings.callbacks[services[i]] = observe;
|
||||
}
|
||||
struct DB_SYNC_INSTANCE* tables[2];
|
||||
for (unsigned g = 0; g < 2; g++) {
|
||||
tables[g] = db_sync_instance_find(server, 111 + g); REQUIRE(tables[g]);
|
||||
REQUIRE(!db_sync_verify(tables[g])); tables[g]->sync_gated = 0;
|
||||
merkle_sync_cancel(server, MT_DATA_MESSAGES, client->node_id, tables[g]->ns);
|
||||
}
|
||||
uint8_t push[10 + DB_WIRE_FIXED + 7] = {ETCP_ID_DB_SYNC};
|
||||
struct db_message_revision revision = {.ver = 1, .nonce = {0x67}};
|
||||
db_write64(push + 1, 112); push[9] = DB_MSG_PUSH;
|
||||
uint8_t* record = push + 10;
|
||||
REQUIRE(!chat_message_id(112, 100, client->node_id, revision.nonce, record));
|
||||
db_write64(record + 32, 100); db_write64(record + 40, client->node_id); memcpy(record + 48, revision.nonce, 16);
|
||||
db_write64(record + 64, 1); db_write32(record + 80, 7); memcpy(record + 84, "history", 7);
|
||||
REQUIRE(!db_sync_sign_message(112, 100, client->node_id, &revision, "history", 7, client->my_ed25519_privkey, record + 91));
|
||||
unsigned before = db_sync_count(tables[1]);
|
||||
REQUIRE(!inject(push, sizeof(push)));
|
||||
check("admitted DB_SYNC PUSH is committed in B", db_sync_count(tables[1]) == before + 1);
|
||||
uint8_t sound[11] = {ETCP_ID_CHAT_SYNC}; db_write64(sound + 1, 112); sound[9] = CS_MSG_SOUND_SETTING; sound[10] = 1;
|
||||
REQUIRE(!inject(sound, sizeof(sound)));
|
||||
struct SI_PEER* p = si_peer_find(tables[1], client->node_id); REQUIRE(p);
|
||||
check("admitted SOUND_SETTING is applied in B", p->sound_on == 1);
|
||||
|
||||
/* ACK адресован своей настоящей записи; чужой допуск не должен менять delivered_peers. */
|
||||
uint8_t signature[64], ack[50] = {ETCP_ID_DB_SYNC};
|
||||
REQUIRE(!db_sync_sign_message(112, 101, server->node_id, &revision, "local", 5, server->my_ed25519_privkey, signature));
|
||||
REQUIRE(!db_sync_insert_signed(tables[1], "local", 5, signature, 64, 101, NULL, &revision));
|
||||
db_write64(ack + 1, 112); ack[9] = DB_MSG_ACK_PUSH;
|
||||
REQUIRE(!chat_message_id(112, 101, server->node_id, revision.nonce, ack + 10)); db_write64(ack + 42, 1);
|
||||
/* Новая версия уже известного сообщения остаётся криптографически корректной после отзыва. */
|
||||
revision.ver = 2; revision.edited_at = 102;
|
||||
db_write64(record + 64, revision.ver); db_write64(record + 72, revision.edited_at);
|
||||
REQUIRE(!db_sync_sign_message(112, 100, client->node_id, &revision, "history", 7, client->my_ed25519_privkey, record + 91));
|
||||
char sql[192]; snprintf(sql, sizeof(sql), "UPDATE peers_112 SET admitted=0 WHERE node_id=%lld", (long long)client->node_id);
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
|
||||
REQUIRE(topo_group_peer_ready(fixture.groups[0][1], client->node_id));
|
||||
REQUIRE(!inject(push, sizeof(push)) && !inject(ack, sizeof(ack)));
|
||||
check("revoked DB_SYNC PUSH cannot edit existing history", key_value(server, "SELECT ver FROM msg_112 WHERE timestamp=100") == 1);
|
||||
check("revoked DB_SYNC ACK cannot acknowledge history", key_value(server, "SELECT delivered_peers FROM msg_112 WHERE timestamp=101") == 0);
|
||||
sound[10] = 0; REQUIRE(!inject(sound, sizeof(sound)));
|
||||
check("revoked SOUND_SETTING cannot change B", si_peer_find(tables[1], client->node_id)->sound_on == 1);
|
||||
merkle_sync_cancel(server, MT_DATA_MESSAGES, client->node_id, "112");
|
||||
uint8_t wake[MS_HEADER] = {ETCP_ID_MEMBER_SYNC}; db_write64(wake + 1, 112); wake[9] = MS_WAKE; wake[22] = MT_DATA_MESSAGES;
|
||||
REQUIRE(!inject(wake, sizeof(wake)));
|
||||
check("revoked MESSAGES cannot create a Merkle session", !ms_find(server->msync, conn, MT_DATA_MESSAGES, 112));
|
||||
check("revoked MESSAGES cannot start locally", merkle_sync_start(server, MT_DATA_MESSAGES, client->node_id, "112", NULL, NULL) < 0);
|
||||
db_write64(sound + 1, 111); REQUIRE(!inject(sound, sizeof(sound)));
|
||||
p = si_peer_find(tables[0], client->node_id);
|
||||
check("neighbouring SOUND_SETTING still works through same ETCP", p && !p->sound_on && fixture.transport->links_up);
|
||||
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, "UPDATE peers_112 SET admitted=1", NULL, NULL, NULL) == SQLITE_OK);
|
||||
REQUIRE(!inject(push, sizeof(push)) && !inject(ack, sizeof(ack)));
|
||||
check("same PUSH and ACK succeed after readmission", key_value(server, "SELECT ver FROM msg_112 WHERE timestamp=100") == 2 &&
|
||||
key_value(server, "SELECT delivered_peers FROM msg_112 WHERE timestamp=101") == 1);
|
||||
merkle_sync_cancel(server, MT_DATA_MESSAGES, client->node_id, "112");
|
||||
REQUIRE(!merkle_sync_start(server, MT_DATA_MESSAGES, client->node_id, "112", NULL, NULL));
|
||||
struct ms_session* session = ms_find(server->msync, conn, MT_DATA_MESSAGES, 112); REQUIRE(session);
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
|
||||
for (unsigned i = 0; i < 20; i++) uasync_poll(fixture.ua, 1);
|
||||
check("revocation before deferred Merkle work prevents transmission", !session->sent_bytes && !session->tx);
|
||||
|
||||
snprintf(sql, sizeof(sql), "UPDATE peers_112 SET admitted=(node_id!=%lld)", (long long)server->node_id);
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
|
||||
db_write64(sound + 1, 112); REQUIRE(!inject(sound, sizeof(sound)));
|
||||
check("revoked self cannot accept SOUND_SETTING", si_peer_find(tables[1], client->node_id)->sound_on == 1);
|
||||
check("revoked self cannot serve MESSAGES", !db_message_peer(server, "112", client->node_id));
|
||||
REQUIRE(sqlite3_exec(server->topo_sqlite_db, "UPDATE peers_112 SET admitted=1", NULL, NULL, NULL) == SQLITE_OK);
|
||||
fixture.groups[0][1]->stopping = 1;
|
||||
REQUIRE(!inject(sound, sizeof(sound)));
|
||||
check("stopping group cannot accept SOUND_SETTING or MESSAGES", si_peer_find(tables[1], client->node_id)->sound_on == 1 &&
|
||||
!db_message_peer(server, "112", client->node_id));
|
||||
fixture.groups[0][1]->stopping = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
|
||||
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO);
|
||||
@@ -984,7 +1080,8 @@ int main(void) {
|
||||
#ifdef __linux__
|
||||
if (!fixture.failed && file_isolation(1)) fixture.failed++;
|
||||
#endif
|
||||
if (!fixture.failed && (attachment_isolation() || transfer_isolation() || dm_isolation() || stop_isolation())) fixture.failed++;
|
||||
if (!fixture.failed && (attachment_isolation() || transfer_isolation() || dm_isolation() || history_isolation() || stop_isolation()))
|
||||
fixture.failed++;
|
||||
}
|
||||
}
|
||||
pthread_mutex_lock(&fixture.disk_mutex); fixture.disk_released = 1; pthread_cond_signal(&fixture.disk_condition);
|
||||
|
||||
Reference in new issue
Block a user