From 5d2522b8de09a0671b0dc28168e9289376a52a38 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 18 Oct 2026 10:39:29 +0200 Subject: [PATCH] Account decrypted copies in media quota and protect active containers --- src/chat/chat_msg.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/chat/chat_msg.c b/src/chat/chat_msg.c index 53b2cdb7..ee44ce71 100644 --- a/src/chat/chat_msg.c +++ b/src/chat/chat_msg.c @@ -34,7 +34,6 @@ void chat_core_submit_media_message(struct UTUN_INSTANCE* inst, struct chat_msg_ static void wh_transcribe_done_cb(void* arg, const char* ch_id, const char* text, int err, const uint8_t reply_id[32]); static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst); -static void chat_media_cache_enforce(struct UTUN_INSTANCE* inst); static void chat_media_cache_reconcile(struct UTUN_INSTANCE* inst); /* ─── счётчик объёма медиакеша (сумма файлов, соответствующих сообщениям) ─── */ @@ -1514,6 +1513,25 @@ static void chat_media_foreach_media_message(struct chat_core_ctx* cc, const cha cb(&f, arg); + if (cc->attachment_initialized && !strcmp(content_type, ENCRYPTED_ATTACHMENT_TYPE)) { + uint8_t crypto_id[16]; + sqlite3_stmt* local = NULL; + if (!chat_attachment_identity(body, dlen, crypto_id) && sqlite3_prepare_v2(cc->db, + "SELECT plain_path FROM attachment_keys WHERE channel=? AND crypto_id=? AND ready=1 AND decrypting=0", + -1, &local, NULL) == SQLITE_OK) { + sqlite3_bind_text(local, 1, ch_id, -1, SQLITE_STATIC); sqlite3_bind_blob(local, 2, crypto_id, 16, SQLITE_STATIC); + int rc = sqlite3_step(local); + if (rc == SQLITE_ROW) { + snprintf(f.full_path, sizeof(f.full_path), "%s", sqlite3_column_text(local, 0)); + size_t prefix = strlen(media_base); + if (!strncmp(f.full_path, media_base, prefix) && f.full_path[prefix] == '/') { + snprintf(f.rel_path, sizeof(f.rel_path), "%s", f.full_path + prefix + 1); cb(&f, arg); + } + } else if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: scan failed rc=%d ch=%s", rc, ch_id); + sqlite3_finalize(local); + } else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: metadata lookup failed ch=%s: %s", ch_id, sqlite3_errmsg(cc->db)); + } + u_free(body); media_index_result_free(&result); } @@ -1638,6 +1656,24 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) { struct cache_rel_list rels = {0}; chat_media_foreach_media_message(cc, media_base, cache_rel_collect_cb, &rels); + /* Ещё не опубликованные контейнеры и их временные файлы принадлежат crypto worker. */ + if (cc->attachment_initialized) { + sqlite3_stmt* active = NULL; + if (sqlite3_prepare_v2(cc->db, "SELECT cipher_path FROM attachment_keys", -1, &active, NULL) == SQLITE_OK) { + int rc; + while ((rc = sqlite3_step(active)) == SQLITE_ROW) { + const char* path = (const char*)sqlite3_column_text(active, 0); + size_t prefix = strlen(media_base); + if (path && !strncmp(path, media_base, prefix) && path[prefix] == '/') { + cache_rel_add(&rels, path + prefix + 1); + char temporary[1040]; snprintf(temporary, sizeof(temporary), "%s.part", path + prefix + 1); + cache_rel_add(&rels, temporary); + } + } + if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: active scan failed rc=%d", rc); + sqlite3_finalize(active); + } else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "encrypted cache: active query failed: %s", sqlite3_errmsg(cc->db)); + } if (rels.count > 1) qsort(rels.items, (size_t)rels.count, sizeof(char*), cache_str_cmp); struct orphan_walk_ctx ow; @@ -1653,10 +1689,11 @@ static void chat_media_cache_cleanup_orphans(struct UTUN_INSTANCE* inst) { u_free(rels.items); } -static void chat_media_cache_enforce(struct UTUN_INSTANCE* inst) { +void chat_media_cache_enforce(struct UTUN_INSTANCE* inst) { struct chat_core_ctx* cc = CC(inst); if (!cc || !cc->initialized || !cc->db || !inst) return; uint64_t limit = inst->config->global.chatserver_storage_total_size; + if (cc->attachment_initialized) cc->media_cache_bytes = chat_media_cache_scan_sum(cc); if (limit == 0 || cc->media_cache_bytes <= limit) { DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "%s: cache limit ok bytes=%llu limit=%llu",