From b6a5f98d419cc6e16441b2147ff9856bf402a957 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 6 Oct 2026 13:57:12 +0200 Subject: [PATCH] Document 16 KiB signed group avatars and 4 KiB wire blocks --- doc/group_avatar.txt | 81 ++++++++++++++++++++++++ tools/chatgui/translations/chatgui_en.ts | 8 +++ 2 files changed, 89 insertions(+) create mode 100644 doc/group_avatar.txt diff --git a/doc/group_avatar.txt b/doc/group_avatar.txt new file mode 100644 index 00000000..b7fb3d01 --- /dev/null +++ b/doc/group_avatar.txt @@ -0,0 +1,81 @@ +Аватарка CHAT-группы +=================== + +Модуль src/chat/group_avatar.c. Картинка — бинарный BLOB до 16384 байт в общей +SQLite каждого участника: channels.avatar_data/version/hash/signature. +Storage-сервер, каталоги файлов и пользовательские квоты не используются. +При старте добавляются отсутствующие колонки одной транзакцией, записи/ключи +каналов сохраняются. channel_put использует UPSERT и сохраняет аватарку, +UI-состояние и локальные приватные ключи; смена публичных ключей существующего +channel_id запрещена. Удаление группы удаляет и её аватарку. + +Право публикации — приватный Ed25519 ключ группы плюс собственное действующее +членство. creator UID/admin-флаг не заменяют ключ. group_avatar_set подписывает: +ASCII "group-avatar-v1" без NUL, group:u64 LE, version:u64 LE, size:u16 LE, bytes. +Версия — max(NTP microseconds/1000, previous+1), ограничена INT64_MAX. +SHA256 считается по картинке; при одинаковой версии побеждает больший SHA256. +Обе конкурирующие записи должны иметь правильную подпись группы; конфликт — WARN. +Публикация одинаковой картинки не создаёт новую версию. Удаление — подписанная +запись с size=0 и новой версией; подпись/версия сохраняются, старый пир не может +восстановить удалённую картинку. Чтение проверяет сохранённый хеш и подпись. + +Транспорт +--------- + +ETCP_RT_ID_GROUP_AVATAR=0x3A, router wire version=1. Отправитель/группа берутся +из проверенного router-заголовка. Все пакеты подписаны ключом узла и зашифрованы +end-to-end; в DATA дополнительно передаётся подпись группы над всей картинкой. +Обмен только между READY-соседями CHAT-группы с действующим подписанным членством. +Любой участник пересылает сохранённую запись, владелец ключа может быть offline. + +Все числа протокола LE. Общая часть, 44 байта: + version:u8=1, command:u8, avatar_version:u64, total_size:u16, SHA256:32. +STATE=1 объявляет локальную версию/хеш; начальное отсутствие — version=0, hash=0. +GET=2 запрашивает актуальную запись. Объявление не меняет БД без полной DATA. +DATA=3 добавляет group_signature:64, offset:u16, block_size:u16, bytes. +DATA header=112 байт. Картинка разбивается на блоки по 4096 байт; последний +короче. Полная картинка 16 КиБ — ровно четыре DATA. Удаление — один DATA без bytes. + +Порядок блоков гарантирует router. Сборка проверяет offset, постоянные version, +total_size/hash/signature и допустимые размеры. До полной сборки прежняя картинка +остаётся в БД. После SHA256/Ed25519 вся запись заменяется одним UPDATE, затем +CHANNEL_UPDATED доставляет изменение GUI и STATE распространяется соседям. +Промежуточные блоки не публикуются, ACK/retransmit каждого блока — только router. + +Отправка заполняет router до нижнего порога send_q count<=0 и ждёт send_ready; +планировщик отправляет максимум четыре пакета за callback. Snapshot отправителя +не меняется при новом локальном обновлении. Максимум 16 tx и отдельно 16 rx +сборок на экземпляр, каждая до 16 КиБ. receive_ready при заполнении rx сохраняет +пакет в router recv_q без продвижения ACK; освобождение слота возобновляет приём. +Несовпадение эпох/закрытие router отменяет незавершённую сборку и начинает сверку. +Эпоха нового контекста берётся из текущей READY-сессии, не сбрасывает первый приём. +Обнаружение соседей/таймауты — таймер 1 с; STATE также раз в 30 с. Нет прогресса +15 с — отмена незавершённого snapshot, повтор запроса/сверки. Остановка сервиса +отменяет таймеры/waiters/call_soon до удаления группы/ядра. + +ChatGUI +------- + +Настройки группы: Upload group avatar/Remove group avatar, предпросмотр и статус. +Кнопки доступны только при локальном приватном ключе. Применение сразу, отдельно +от Save локальных настроек. Worker обрезает центральный квадрат, создаёт JPEG +128×128, снижает качество/размер до лимита 16 КиБ. Вход ограничен 16 мегапикселями. +GUI отправляет байты в uasync; ядро повторно проверяет размер/членство/ключ. + +SQLite — постоянный кеш. GroupAvatarManager хранит QImage до 32 МиБ, ключ кеша: +group/version/hash. Декодирование в отдельном worker, проверка SHA256, JPEG и +квадратных размеров до 128×128. Поздний результат старой версии не заменяет +новую. Готовая картинка обновляет только строку группы; без аватарки — инициалы. +Приватные ключи/байты картинки не выводятся в диагностику. + +Проверки +-------- + +test_group_avatar: настоящие два ядра/UDP/router, 16 КиБ четырьмя блоками, +атомарность сборки, hash/signature/cross-group отказ, приостановка receive, +перезапуск канала, stale/conflict, редактор с ключом вне creator UID, подписанное +удаление, повторное описание группы и restart БД. Schema failure откатывает +частичные ALTER, сохраняет прежние данные/ключи, повторное добавление идемпотентно. +test_group_avatars (Qt): нормализация, лимит/отображение, кеш, права кнопок и отказ +ядра без ключа, удаление. chat=debug показывает состояния и каждый 4КиБ блок; +chat=info — публикации и жизненный цикл. Ошибки содержат group/peer/version/offset. diff --git a/tools/chatgui/translations/chatgui_en.ts b/tools/chatgui/translations/chatgui_en.ts index b770e76d..d9f743ab 100644 --- a/tools/chatgui/translations/chatgui_en.ts +++ b/tools/chatgui/translations/chatgui_en.ts @@ -2107,5 +2107,13 @@ Directories: %5 Cannot prepare avatar: %1Cannot prepare avatar: %1 Avatar upload failed: %1Avatar upload failed: %1 Avatar updatedAvatar updated + Upload group avatarUpload group avatar + Remove group avatarRemove group avatar + Group avatar: up to 16 KiB. Changes apply immediately and require the group key.Group avatar: up to 16 KiB. Changes apply immediately and require the group key. + Preparing group avatar…Preparing group avatar… + Saving group avatar…Saving group avatar… + Cannot update group avatarCannot update group avatar + Group avatar updatedGroup avatar updated + Chat is stoppedChat is stopped