Retry failed decryption after a newly verified download

This commit is contained in:
evgeny committed 2026-10-27 02:31:29 +01:00
1 parent b31f974a44
commit 78d0e3f54f
3 files changed
+19 -14

No files matched your search

+12 -8
View File
@@ -988,7 +988,7 @@ fail:
}
/* Автозагрузка обычного участника запрашивает доступ; storage-реплика хранит только ciphertext. */
int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32]) {
int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], int verified_download) {
if (!inst || !CC(inst) || CC(inst)->attachment_closing || !ak_channel(channel) || !message) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: invalid downloaded state/arguments"); return -1;
}
@@ -999,7 +999,7 @@ int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel,
const char* stage = "begin downloaded";
int rc = sqlite3_exec(db, "BEGIN IMMEDIATE /* attachment downloaded */", NULL, NULL, NULL);
if (rc != SQLITE_OK) goto fail;
char sql[512]; snprintf(sql, sizeof(sql), "SELECT downloaded,wanted,NOT EXISTS(SELECT 1 FROM peers_%s"
char sql[512]; snprintf(sql, sizeof(sql), "SELECT downloaded,wanted,error,NOT EXISTS(SELECT 1 FROM peers_%s"
" WHERE node_id=? AND source=0 AND deleted=0 AND length(adm_tags_sig)=64 AND json_extract(adm_tags,'$.storage')='yes')"
" FROM attachment_keys WHERE channel=? AND message_id=?", channel);
stage = "prepare download state"; rc = sqlite3_prepare_v2(db, sql, -1, &st, NULL);
@@ -1012,20 +1012,23 @@ int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel,
if (rc != SQLITE_OK) goto fail;
stage = "read download state"; rc = sqlite3_step(st);
if (rc != SQLITE_ROW) goto fail;
int downloaded = sqlite3_column_int(st, 0), wanted = sqlite3_column_int(st, 1), automatic = sqlite3_column_int(st, 2);
int downloaded = sqlite3_column_int(st, 0), wanted = sqlite3_column_int(st, 1), error = sqlite3_column_int(st, 2);
int automatic = sqlite3_column_int(st, 3), desired_error = verified_download ? 0 : error;
if ((downloaded != 0 && downloaded != 1) || (wanted != 0 && wanted != 1)) { stage = "download state"; rc = SQLITE_MISMATCH; goto fail; }
int desired = wanted || automatic, changed_state = !downloaded || wanted != desired;
int desired = wanted || automatic, changed_state = !downloaded || wanted != desired || error != desired_error;
stage = "finalize download state"; rc = sqlite3_finalize(st); st = NULL;
if (rc != SQLITE_OK) goto fail;
if (changed_state) {
stage = "prepare downloaded";
rc = sqlite3_prepare_v2(db, "UPDATE attachment_keys SET downloaded=1,wanted=? WHERE channel=? AND message_id=?", -1, &st, NULL);
rc = sqlite3_prepare_v2(db, "UPDATE attachment_keys SET downloaded=1,wanted=?,error=? WHERE channel=? AND message_id=?", -1, &st, NULL);
if (rc != SQLITE_OK) goto fail;
stage = "bind wanted"; rc = sqlite3_bind_int(st, 1, desired);
if (rc != SQLITE_OK) goto fail;
stage = "bind channel"; rc = sqlite3_bind_text(st, 2, channel, -1, SQLITE_STATIC);
stage = "bind error"; rc = sqlite3_bind_int(st, 2, desired_error);
if (rc != SQLITE_OK) goto fail;
stage = "bind message"; rc = sqlite3_bind_blob(st, 3, message, 32, SQLITE_STATIC);
stage = "bind channel"; rc = sqlite3_bind_text(st, 3, channel, -1, SQLITE_STATIC);
if (rc != SQLITE_OK) goto fail;
stage = "bind message"; rc = sqlite3_bind_blob(st, 4, message, 32, SQLITE_STATIC);
if (rc != SQLITE_OK) goto fail;
stage = "write downloaded"; rc = sqlite3_step(st);
if (rc != SQLITE_DONE) goto fail;
@@ -1037,7 +1040,8 @@ int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel,
stage = "commit downloaded"; rc = sqlite3_exec(db, "COMMIT /* attachment downloaded */", NULL, NULL, NULL);
if (rc != SQLITE_OK) goto fail;
if (changed_state) {
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "attachment keys: download state committed channel=%s wanted=%d automatic=%d", channel, desired, automatic);
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "attachment keys: download state committed channel=%s wanted=%d automatic=%d verified=%d error=%d",
channel, desired, automatic, verified_download != 0, desired_error);
ak_changed(inst, channel);
}
return 0;
+3 -2
View File
@@ -66,10 +66,11 @@ int chat_attachment_observe(struct UTUN_INSTANCE* inst, const char* channel, con
// ── Получение файла и выдача доступа ──
/* После проверенной загрузки/наличия сохранённого контейнера: своей транзакцией сохранить downloaded и policy wanted.
/* После загрузки/наличия сохранённого контейнера: своей транзакцией сохранить downloaded и policy wanted.
* 0/-1; запись observe обязательна. Повтор неизменного состояния не даёт события. Криптографию проверит worker.
* verified_download!=0 — новая проверенная передача, также сбрасывает прежний error; 0 — найденный cache, error сохраняется.
* Внешняя транзакция запрещена, SQL-отказ сохраняет прежние поля, событие — после commit. */
int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32]);
int chat_attachment_downloaded(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message[32], int verified_download);
/* Ручная загрузка, включая storage: одной транзакцией установить wanted, сбросить error и ready отсутствующего cache.
* 0/-1; запись observe обязательна. Внешняя транзакция запрещена, отказ сохраняет прежние поля. */
+4 -4
View File
@@ -778,7 +778,7 @@ static void md_download_done_cb(void* arg, int err) {
struct chat_core_ctx* cc = CC(ctx->inst);
if (!err) {
if (!strcmp(ctx->content_type, ENCRYPTED_ATTACHMENT_TYPE)) {
if (chat_attachment_downloaded(ctx->inst, ctx->channel_id, ctx->message_id))
if (chat_attachment_downloaded(ctx->inst, ctx->channel_id, ctx->message_id, 1))
media_queue_channel_backfill(ctx->inst, ctx->channel_id);
}
char attrs[1024];
@@ -1187,7 +1187,7 @@ void chat_core_attachment_download(struct UTUN_INSTANCE* inst, const char* chann
channel_id, rc, finish, sqlite3_errmsg(cc->db)); u_free(body); return;
}
if (present) {
if (chat_attachment_downloaded(inst, channel_id, message)) media_queue_channel_backfill(inst, channel_id);
if (chat_attachment_downloaded(inst, channel_id, message, 0)) media_queue_channel_backfill(inst, channel_id);
u_free(body); return;
}
}
@@ -1297,7 +1297,7 @@ void chat_media_backfill(struct UTUN_INSTANCE* inst) {
int registered = media_index_commit(cc->db, &result, cc->my_node_id, NULL, ch_id, path, media_base);
if (!registered) total += result.num_blocks;
else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media backfill registration failed ch=%s file=%s", ch_id, path);
if (encrypted_attachment && !registered && chat_attachment_downloaded(inst, ch_id, message))
if (encrypted_attachment && !registered && chat_attachment_downloaded(inst, ch_id, message, 0))
media_queue_channel_backfill(inst, ch_id);
u_free(body);
@@ -1416,7 +1416,7 @@ static void bf_collect(struct chat_core_ctx* cc, const char* media_base, const c
snprintf(full_path, sizeof(full_path), "%s/media/%s/%s", media_base, ch_id, final_name);
int64_t actual = ma_file_size(full_path);
if (actual < 0) actual = 0;
if (encrypted_attachment && actual > 0 && chat_attachment_downloaded(cc->inst, ch_id, message))
if (encrypted_attachment && actual > 0 && chat_attachment_downloaded(cc->inst, ch_id, message, 0))
media_queue_channel_backfill(cc->inst, ch_id);
if (l->count == l->cap) {