diff --git a/doc/encrypted_attachments.md b/doc/encrypted_attachments.md index 11bddc81..2bf94812 100644 --- a/doc/encrypted_attachments.md +++ b/doc/encrypted_attachments.md @@ -45,8 +45,26 @@ Nonce метаданных использует `part=UINT64_MAX`; файл — Получатель проверяет подписанный SHA256 полного контейнера, UUID, tag метаданных, все tags файла, точный размер и hash тела. Результат пишется во временный файл -и публикуется после успешной проверки и durable rename. Все длительные файловые -операции и криптография выполняются в media_async. +и публикуется после успешной проверки и durable rename. Подготовка файлов +и криптография выполняются в media_async worker. + +`encrypted_file_write/read` возвращают закрытый проверенный `file_io_temp`, +не изменяя конечное назначение. Задача владеет им до publish/discard; запись идёт +в эксклюзивно созданный соседний файл с правами 0600 на POSIX. Одинаковые файлы, +включая `/./`, hardlink и конечную ссылку назначения, отклоняются до подготовки; +публикация повторно проверяет идентичность. При ошибке read не выдаёт новые метаданные. + +Режим `FILE_IO_DURABLE` действует весь срок temp: flush/sync открытого файла/close, +затем rename и сохранение каталога. После успешного rename ошибка directory sync +не откатывает установленный результат; temp уже отсоединён от владельца. +Completion не удаляет файлы по заранее вычисленному имени: очистка учитывает, +какие артефакты задача действительно создала или опубликовала. + +Реестр `file_io` защищает активные temp от очистки кеша, включая время после close. +Восстановление до запуска workers и очистка после их завершения удаляют оставшиеся +`.uenc.tmp.` / `.file.tmp.` в `media/decrypted`. +Конечные файлы и имена других форматов этот проход сохраняет; активные temp другого +instance того же процесса остаются защищены общим реестром. ## Хранение и разрешения @@ -110,9 +128,14 @@ backpressure и повтором через 5 секунд; restart продол `test_encrypted_file`: границы порций, пустой файл, metadata roundtrip, неверные ключ/автор/UUID/hash, подмена метаданных с пересчитанным внешним hash, -лишние байты и отсутствие частичного plaintext после отказа. +лишние байты, alias обоих API, сохранность существующего назначения/метаданных, +23 сценария отказов I/O с контролем fd/temp, включая ошибку после rename. +`test_media_primitives` проверяет оба режима temp и границу durable-публикации; +`test_attachment_send` останавливает сервис после настоящего crypto rename до completion. `test_encrypted_attachment`: реальные A–S–B/C, скачивание с S при выключенном A, перезапуски автора с запросами и получателя с ключом, выдача B и отказ C, отсутствие ключа на S/C, отрицательные control-пакеты, повтор GRANT, восстановление удалённого plaintext без нового согласия и удаление канала. +При startup/restart дополнительно проверяются оба дерева: stale temp удаляются, +открытый и закрытый активные temp, конечные файлы и чужие имена сохраняются. diff --git a/doc/service_lifecycle.md b/doc/service_lifecycle.md index 26eb6d8c..b754d28a 100644 --- a/doc/service_lifecycle.md +++ b/doc/service_lifecycle.md @@ -136,6 +136,15 @@ completion. Отказ запуска/неверные аргументы даю закрытия temp; вызывающий отвечает за очистку своего результата при отмене. Подробные файловые контракты, 64-битные размеры и ошибки RNG описаны в `media_async.h`. +Групповой crypto worker хранит один `file_io_temp` прямо в задаче вложения. +`encrypted_file_write/read` только готовят закрытый durable temp; worker публикует +его одним rename, completion подтверждает результат в БД/UI. Отмена до completion +не публикует сообщение; cleanup учитывает реально созданные/заменённые файлы. +Ошибка синхронизации каталога после rename означает установленное имя без подтверждённой +durability; отложенный discard уже не удаляет результат. Общей транзакции ФС/БД нет. +До запуска workers и после их завершения recovery очищает собственные stale temp +в `media/decrypted`; общий file_io-реестр сохраняет активные temp всех instance. + `media_delivery_init()` вызывается после подготовки chat core и media_index, пока общая БД и группы живы; подписка на роли обязательна. Репликация хранит отдельный контекст и CM handle для каждой пары «CHAT-группа–пир». DOWN отменяет текущий RPC,