Clarify attachment commit ownership and SQL failure diagnostics

This commit is contained in:
evgeny committed 2026-10-26 22:10:44 +01:00
1 parent e5ca2e174c
commit 71dfc9d70d
2 files changed
+29 -13

No files matched your search

+23 -10
View File
@@ -14,16 +14,23 @@ Android показывает зашифрованное вложение отд
Список чатов сохраняет общее название зашифрованного вложения вместо manifest.
Автор генерирует независимые случайные crypto_UUID и ключ AES-256 на каждую
подготовку. Штатно ключ записывается в локальную SQLite до шифрования. При аудите
26.10.2026 подтверждено исключение: отказ `sqlite3_bind_blob` ключа не проверяется,
и подготовка запускается со строкой `key=NULL`, несмотря на сообщение «key saved».
Контейнер создаётся, переданный исходник удаляется; последующая проверка
`chat_attachment_bind` запрещает публикацию, и отправка завершается событием ошибки.
Это открытый дефект сохранения ключа; аудит модуля остаётся частичным.
Стенд, точная граница проверки и план исправления — в
[chat_audit_findings.txt](chat_audit_findings.txt), продолжение chat_attachment.
Готовый контейнер
передаётся через обычные media_index/media_delivery. UUID транспортного медиа
подготовку. Ключ, UUID, автор, пути и метаданные записываются в локальную SQLite
собственной короткой транзакцией до передачи подготовленного файла worker.
Проверяются prepare, все bind, step, ровно одна добавленная строка, finalize и commit.
Внешняя транзакция отклоняется без изменений. До принятия ошибка возвращает `-1`:
файл остаётся у вызывающего, worker и событие отправки не создаются.
После commit возвращается `0`, файл принадлежит задаче и удаляется также при её отказе;
ненулевой request получает один `MSG_SUBMITTED`, в том числе синхронно при отказе запуска worker.
Исходный пользовательский файл сохраняется: общий frontend передаёт сюда собственную подготовленную копию.
Неудачный rollback с оставшейся открытой транзакцией отключает модуль вложений и
запрашивает остановку ядра. Desktop и Android учитывают запрос в своих poll-циклах;
владелец освобождает ядро и закрывает SQLite после возврата из poll. Текущий poll может
доставить другие callbacks до выхода. Политика общей БД остаётся WAL/synchronous=NORMAL:
завершённый commit до worker не является гарантией сохранности после отключения питания.
История дефекта и проверок — в [chat_audit_findings.txt](chat_audit_findings.txt).
Готовый контейнер передаётся через обычные media_index/media_delivery. UUID транспортного медиа
и crypto_UUID имеют разные назначения: первый идентифицирует сетевые блоки,
второй — контейнер и ключ. Повтор доставки передаёт прежний контейнер.
@@ -154,6 +161,12 @@ backpressure и повтором через 5 секунд; restart продол
`test_attachment_send` проверяет восемь отказов MIME до ключей/worker/файлов,
затем останавливает сервис после настоящего crypto rename до completion.
`test_chat_attachment` проверяет 13 SQL-отказов с сохранением source/прежних строк/файлов,
отсутствием worker и события до принятия, затем настоящую публикацию при каждом повторе.
Отдельное readonly-соединение проверяет точные ключ, автора, UUID, метаданные и пути до worker.
Дополнительно проверяются настоящий commit veto, INSERT ABORT/IGNORE, внешняя транзакция,
синхронный отказ запуска, restart с опубликованным ключом и отказ rollback с закрытием БД владельцем.
`test_encrypted_attachment`: реальные A–S–B/C, скачивание с S при выключенном A,
перезапуски автора с запросами и получателя с ключом, выдача B и отказ C,
отсутствие ключа на S/C, отрицательные control-пакеты, повтор GRANT,
+6 -3
View File
@@ -236,16 +236,19 @@ static int ak_store_preparation(struct ak_file* job, const uint8_t* info, int in
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "attachment keys: author preparation committed before encryption channel=%s", job->channel);
return 0;
fail:
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: preparation channel=%s stage=%s rc=%d: %s", job->channel, stage, rc, sqlite3_errmsg(db));
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: preparation channel=%s stage=%s rc=%d (%s) db=%s",
job->channel, stage, rc, sqlite3_errstr(rc), sqlite3_errmsg(db));
int final_rc = sqlite3_finalize(st);
if (final_rc != SQLITE_OK)
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: preparation cleanup finalize channel=%s rc=%d", job->channel, final_rc);
if (!sqlite3_get_autocommit(db)) {
int rollback_rc = sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL);
if (rollback_rc != SQLITE_OK)
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: preparation rollback channel=%s rc=%d: %s", job->channel, rollback_rc, sqlite3_errmsg(db));
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: preparation rollback channel=%s rc=%d (%s) db=%s",
job->channel, rollback_rc, sqlite3_errstr(rollback_rc), sqlite3_errmsg(db));
if (!sqlite3_get_autocommit(db)) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: transaction remains open channel=%s; quiescing attachments and requesting core stop", job->channel);
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: transaction remains open channel=%s; quiescing attachments and requesting core stop",
job->channel);
chat_attachment_quiesce(inst);
utun_instance_stop(inst);
}