diff --git a/src/chat/chat_msg.c b/src/chat/chat_msg.c index 2f1eb9af..53b2cdb7 100644 --- a/src/chat/chat_msg.c +++ b/src/chat/chat_msg.c @@ -5,6 +5,7 @@ */ #include "chat_core_priv.h" +#include "chat_attachment.h" #include "chat_event.h" #include "chat_feedback.h" #include "chat_poll.h" @@ -266,6 +267,15 @@ static void on_media_registered(void* arg, int err, const struct media_index_res const char* filename = base ? base + 1 : mctx->media_dest; char attrs[1100]; snprintf(attrs, sizeof(attrs), "{\"st\":\"fl\",\"fp\":\"%s\"}", filename); + if (!strcmp(mctx->content_type, ENCRYPTED_ATTACHMENT_TYPE)) { + uint8_t crypto_id[16], message_id[32]; + if (chat_attachment_identity(full_data, full_data_len, crypto_id) || + chat_message_id(db_sync_instance_group_id(si), ts, json_sig, message_id) || + chat_attachment_bind(mctx->inst, mctx->channel_id, crypto_id, message_id, result->content_hash)) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted media: cannot publish without bound author key ch=%s", mctx->channel_id); + u_free(sig_msg); u_free(json); u_free(full_data); media_submit_finish(mctx, 0); return; + } + } int ret = db_sync_insert_signed(si, json, strlen(json), json_sig, 64, ts, attrs); if (ret != 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: media insert failed ret=%d", CC_ID, ret); @@ -680,6 +690,11 @@ static void md_download_done_cb(void* arg, int err) { struct md_done_ctx* ctx = (struct md_done_ctx*)arg; struct chat_core_ctx* cc = CC(ctx->inst); if (!err) { + if (!strcmp(ctx->content_type, ENCRYPTED_ATTACHMENT_TYPE)) { + uint8_t message[32]; + if (!chat_message_id(strtoull(ctx->channel_id, NULL, 10), ctx->ts, ctx->author_sig, message)) + chat_attachment_downloaded(ctx->inst, ctx->channel_id, message); + } char attrs[1024]; snprintf(attrs, sizeof(attrs), "{\"st\":\"fl\",\"fp\":\"%s\"}", ctx->dest_relpath); chat_core_update_local_attrs(ctx->inst, ctx->channel_id, ctx->ts, ctx->author_sig, attrs); @@ -783,7 +798,7 @@ static void extract_base_filename(const char* body, char* out, size_t out_sz) { /* Разбор тела "d" медиасообщения в media_index_result. Формат: * ||||||,,... * Выделяет result->block_ids/block_sigs (освобождать через media_index_result_free). */ -static int chat_msg_parse_media_body(const char* body, struct media_index_result* result) { +int chat_msg_parse_media_body(const char* body, struct media_index_result* result) { memset(result, 0, sizeof(*result)); if (!body) return -1; const char* p = body; @@ -917,6 +932,9 @@ void on_msg_inserted(struct DB_SYNC_INSTANCE* si, const uint8_t message_id[32], struct chat_core_ctx* cc = CC(inst); if (!cc) return; char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)db_sync_instance_group_id(si)); + if (chat_attachment_observe(inst, ch_id, message_id, author, data, len)) { + DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "encrypted media: invalid manifest ch=%s", ch_id); return; + } chat_feedback_check_message(inst, ch_id, message_id); uint8_t evt[73]; uint8_t cl = (uint8_t)strlen(ch_id); evt[0] = cl; memcpy(evt + 1, ch_id, cl); memcpy(evt + 1 + cl, &author, 8); @@ -1041,6 +1059,20 @@ void chat_core_attachment_download(struct UTUN_INSTANCE* inst, const char* chann uint8_t author_sig[64]; memcpy(author_sig, sig_blob, 64); sqlite3_finalize(st); + if (!strcmp(content_type, ENCRYPTED_ATTACHMENT_TYPE)) { + uint8_t message[32]; + if (chat_message_id(strtoull(channel_id, NULL, 10), (uint64_t)db_ts, author_sig, message)) return; + chat_attachment_want(inst, channel_id, message); + sqlite3_stmt* encrypted = NULL; + if (sqlite3_prepare_v2(cc->db, "SELECT cipher_path FROM attachment_keys WHERE channel=? AND message_id=? AND downloaded=1", + -1, &encrypted, NULL) == SQLITE_OK) { + sqlite3_bind_text(encrypted, 1, channel_id, -1, SQLITE_STATIC); sqlite3_bind_blob(encrypted, 2, message, 32, SQLITE_STATIC); + int present = sqlite3_step(encrypted) == SQLITE_ROW && ma_file_size((const char*)sqlite3_column_text(encrypted, 0)) > 0; + sqlite3_finalize(encrypted); + if (present) { chat_attachment_downloaded(inst, channel_id, message); return; } + } else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted media: local file lookup failed: %s", sqlite3_errmsg(cc->db)); + } + /* сбрасываем пометку «файл есть»: файл мог быть вычищен кешем, а local_attrs ещё "fl". по завершении md_download_done_cb снова запишет st=fl (успех) или st=er (ошибка). */ chat_core_update_local_attrs(inst, channel_id, (uint64_t)db_ts, author_sig, "{}");