Этап 5: история — экспорт и импорт .bare, устройства, место, пагинация
Экспорт: ключ архива из секрета аккаунта через HKDF, заголовок ровно 65 байт (magic, версия, соль, 32 сырых байта отпечатка владельца, iv) и он же целиком AAD шифротекста. Ника владельца в файле нет. Импорт сверяет отпечаток до расшифровки, сливает идемпотентно по id, а записи peers берёт только для ников, которых в локальном TOFU ещё нет: архивом доверие к ключу не перебить. Настройки: устройства с датой и пометкой «это устройство», «занято N МБ», кнопка «экспортировать» в подтверждении выхода и в подтверждении входа под другим ником — долг этапа 1 и обещание ADR-029 закрыты. Лента: страницы по 50 с подгрузкой вверх без прыжка прокрутки; новая страница вставляется, а не пересобирает ленту. ADR-050: импорт не перезаписывает лежащую запись — у своей есть состояние отправки, которого в архиве нет. ADR-054: архив — недоверенный ввод. Ревью собрало архивы с ts вне диапазона Date, мусорным lastId, ником с bidi-переопределением и roomId с обходом пути: каждый из них навсегда ломал ленту или счётчик. Теперь форма ника, roomId, id, ts и автора проверяется, а lastId из файла не читается вовсе. ADR-051, 052, 053: тексты и кнопки, устройства и место, страницы ленты без виртуализации. Приёмка: формат сверен побайтно на модулях, скачанных с боевого сервера, — смещения заголовка, отпечаток сырыми байтами, новые соль и iv на каждый экспорт, подмена любого байта заголовка ломает расшифровку, чужой секрет не открывает, семь видов битых файлов отвергнуты. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DbCjVfTFq4ZFG8juD45YJ
This commit is contained in:
+19
-2
@@ -98,8 +98,11 @@ const bus = new EventTarget();
|
||||
//
|
||||
// "net" {online} — доходят ли запросы до сервера
|
||||
// "chats" {} — список чатов изменился
|
||||
// "messages" {chatId, ids, removed} — в чате появились, изменились
|
||||
// или исчезли сообщения
|
||||
// "messages" {chatId, ids, removed, whole}
|
||||
// — в чате появились, изменились
|
||||
// или исчезли сообщения; whole
|
||||
// означает «перечитай ленту
|
||||
// целиком», без перечня (ADR-050)
|
||||
// "peers" {nick} — доверие к ключу ника изменилось:
|
||||
// появился pending или его подтвердили
|
||||
// "rooms" {id} — комната изменилась: имя, состав,
|
||||
@@ -174,6 +177,20 @@ function announceRoom(id) {
|
||||
share({ kind: "rooms", id, blocked: needsTrust(id) });
|
||||
}
|
||||
|
||||
// imported — импорт архива влил историю в базу (ADR-050). Перечня
|
||||
// добавленного в событии нет: сообщений бывает несколько тысяч и они
|
||||
// старые, поэтому лента перечитывается целиком, а не строка за строкой.
|
||||
// Запись сделал export.js, здесь остаётся поднять экраны — свои
|
||||
// и соседних вкладок (ADR-035).
|
||||
export function imported(chatIds) {
|
||||
const details = chatIds.map((chatId) => ({ chatId, ids: [], removed: [], whole: true }));
|
||||
for (const detail of details) {
|
||||
emit("messages", detail);
|
||||
}
|
||||
emit("chats");
|
||||
share({ kind: "changed", details, settled: [] });
|
||||
}
|
||||
|
||||
// --- соседние вкладки ---------------------------------------------------
|
||||
|
||||
// share отдаёт изменение соседним вкладкам. Канал открыт, только пока
|
||||
|
||||
Reference in New Issue
Block a user