Accept subgroup messages and distinguish own device replicas

This commit is contained in:
evgeny committed 2026-11-03 12:32:53 +01:00
1 parent 02087b1878
commit 7e508f720d
2 files changed
+33 -11

No files matched your search

+32 -10
View File
@@ -542,7 +542,11 @@ int dm_accept_message(struct UTUN_INSTANCE* inst, const uint8_t* msg, size_t len
return -1;
}
if (dm_verify_message(inst, inst->node_id, msg, len) != 0) return -1;
int deleted = dm_history_deleted(inst, msg, len, 0, NULL);
struct dm_message_view message;
if (dm_message_parse(msg, len, &message)) return -1;
int side = message.mode == DM_MODE_GROUPS ? dm_message_target(&message, inst->node_id, NULL, NULL) : 1;
int dir = side == 0;
int deleted = dm_history_deleted(inst, msg, len, dir, NULL);
if (deleted < 0) return -1;
uint64_t conv, seq, author;
memcpy(&conv, msg, 8);
@@ -558,38 +562,56 @@ int dm_accept_message(struct UTUN_INSTANCE* inst, const uint8_t* msg, size_t len
if (created) {
memset(&c, 0, sizeof(c));
snprintf(c.conv_id, sizeof(c.conv_id), "%s", conv_id);
c.mode = message.mode;
c.peer_node_id = author;
if (!dm_shared_group_id(dm, author, &c.group_id)) {
DEBUG_WARN(DEBUG_CATEGORY_DM, "%s: unknown correspondent peer=%llu", DM_ID, (unsigned long long)author);
return -1;
}
if (dm_node_pubkeys(dm, author, c.peer_x25519, c.peer_ed25519) != 0 ||
if (c.mode == DM_MODE_GROUPS) {
c.parties[0] = message.parties[side]; c.parties[1] = message.parties[1 - side];
if (!side) {
c.peer_node_id = 0;
for (unsigned i = 0; i < message.target_count; i++) {
struct dm_target target;
if (dm_message_target_at(&message, i, &target)) return -1;
if (target.side == 1) { c.peer_node_id = target.node; break; }
}
}
memcpy(c.peer_x25519, c.parties[1].x, 32); memcpy(c.peer_ed25519, c.parties[1].ed, 32);
uint8_t private_key[32];
if (dm_party_private(inst, c.parties, private_key)) return -1;
int error = dm_derive_content_key(private_key, c.parties[1].x, c.content_key);
OPENSSL_cleanse(private_key, sizeof(private_key));
if (error) return -1;
} else if (dm_node_pubkeys(dm, author, c.peer_x25519, c.peer_ed25519) != 0 ||
dm_derive_content_key(inst->my_keys.private_key, c.peer_x25519, c.content_key) != 0) return -1;
char name[128] = {0};
chat_core_get_node_name(inst, author, name, sizeof(name));
chat_core_get_node_name(inst, c.peer_node_id, name, sizeof(name));
dm_copy_peer_name(c.peer_name, name, strlen(name), conv_id);
}
if (c.peer_node_id != author) {
if (c.mode != message.mode || (c.mode == DM_MODE_DEVICE && c.peer_node_id != author) ||
(c.mode == DM_MODE_GROUPS && (!dm_party_equal(c.parties, message.parties + side) ||
!dm_party_equal(c.parties + 1, message.parties + 1 - side)))) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: conversation author mismatch conv=%s", DM_ID, conv_id);
return -1;
}
uint16_t enc_len;
memcpy(&enc_len, msg + 33 + msg[32], 2);
if (!dm_conv_active(dm, &c)) return -1;
uint8_t nonce[DM_NONCE_SIZE], plain[DM_DATA_MAX + 1];
size_t plain_len = 0;
dm_build_nonce(conv, author, seq, nonce);
if (media_ccm_decrypt(c.content_key, nonce, msg + 35 + msg[32], enc_len, plain, &plain_len) != 0) return -1;
if (media_ccm_decrypt(c.content_key, nonce, message.ciphertext, message.ciphertext_size, plain, &plain_len) != 0) return -1;
if (dm_message_media(msg, len)) {
struct attachment_info info;
if (attachment_decode(plain, plain_len, &info)) return -1;
}
if (dm_exec(dm, "BEGIN IMMEDIATE") != 0) return -1;
int inserted = dm_store_message(dm, conv_id, 0, msg, len);
if (seq > c.last_in_seq) c.last_in_seq = seq; /* Только статистика; не курсор dedup. */
int inserted = dm_store_message(dm, conv_id, dir, msg, len);
if (!dir && seq > c.last_in_seq) c.last_in_seq = seq; /* Только статистика; не курсор dedup. */
uint64_t ts;
memcpy(&ts, msg + 16, 8);
if (ts > c.last_ts) c.last_ts = ts;
if (inserted < 0 || dm_conv_save(dm, &c) != 0 || dm_media_track(inst, 0, msg, len) != 0 ||
if (inserted < 0 || dm_conv_save(dm, &c) != 0 || dm_media_track(inst, dir, msg, len) != 0 ||
(inserted && dm_history_show(inst, conv_id)) || dm_exec(dm, "COMMIT") != 0) {
dm_exec(dm, "ROLLBACK");
return -1;
+1 -1
View File
@@ -19,7 +19,7 @@ int dm_history_init(struct UTUN_INSTANCE* inst) {
const char* sql =
"CREATE TABLE IF NOT EXISTS dm_history(conv_id TEXT PRIMARY KEY,generation INTEGER NOT NULL,hidden INTEGER NOT NULL);"
"CREATE TABLE IF NOT EXISTS dm_deleted_messages(conv_id TEXT NOT NULL,dir INTEGER NOT NULL,seq INTEGER NOT NULL,"
"body_hash BLOB NOT NULL,media_id BLOB,media_receipt BLOB,PRIMARY KEY(conv_id,dir,seq));"
"author INTEGER NOT NULL,body_hash BLOB NOT NULL,media_id BLOB,media_receipt BLOB,PRIMARY KEY(conv_id,author,seq));"
"CREATE TABLE IF NOT EXISTS dm_local_files(path TEXT PRIMARY KEY,conv_id TEXT NOT NULL,generation INTEGER NOT NULL,"
"busy INTEGER NOT NULL DEFAULT 0,retry_at INTEGER NOT NULL DEFAULT 0);"
"UPDATE dm_local_files SET busy=0;";