# Технические вставки внутри plaintext DM v1 ## Статус документа Этот файл описывает внутренний формат технических вставок, которые находятся внутри уже расшифрованного plaintext DM. Важно: - это не отдельный серверный DM-envelope; - это часть plaintext контентного DM после E2EE-расшифровки; - сервер не обязан знать этот формат; - клиент может использовать эти вставки для специального UI-рендера. ## 1. Общий принцип Обычное сообщение по-прежнему остаётся обычным текстом. Если в начале plaintext стоит один или несколько специальных блоков формата: ```text ``` то клиент трактует их как технические вставки. Техническими считаются только блоки, которые: - стоят строго в начале plaintext; - начинаются с префикса ``. Если текст не начинается с `` или `` в начале plaintext: - не показываются пользователю как сырой текст; - используются клиентом для UI-логики; - неизвестные будущие типы тоже скрываются, если они распознаны как корректный SHiNE-блок. Если блок битый и не закрыт символом `>`, он не считается техническим и сообщение показывается как обычный текст целиком. ## 3. Защита от случайного пользовательского ввода Перед отправкой обычного текстового сообщения клиент обязан проверить: - если пользовательский текст начинается с ` ``` Правила: - `kind` — ASCII-идентификатор типа вставки; - параметры отделяются `;`; - ключ и значение отделяются `=`; - значения обычных v1-вставок не экранируются; для `file` поля `url`, `name`, `mime` кодируются через percent-encoding (`encodeURIComponent`), чтобы `;`, `=` и `>` внутри метаданных не ломали блок; - канонический новый префикс: `Текст ответа ``` Где поле `id` — это логический идентификатор сообщения: ```text fromLogin|toLogin|timeMs|nonce ``` Правила: - этот блок должен стоять в начале plaintext; - после него может идти обычный текст ответа; - официальный UI формирует такой блок при отправке ответа через пункт `Ответить` в меню сообщения; - если клиент не находит сообщение, на которое ссылается `reply`, он просто не показывает reply-preview; - в таком случае само сообщение отображается как обычный текст без блока ``. ## 6. Тип `call` ### Успешный звонок ```text ``` Где: - `duration` — длительность разговора в секундах. ### Неуспешный звонок ```text ``` Допустимые причины в v1: - `offline` - `no_answer` - `connect_failed` - `busy` - `declined` Правила: - call-блок в v1 должен содержать только техническую запись звонка; - пользовательский текст после такого блока в штатной логике не предполагается; - UI может рисовать такие сообщения отдельным специальным стилем. - официальный UI не отправляет call-summary, если от старта исходящего звонка до его завершения прошло меньше `5` секунд. ## 7. Тип `file` Формат v1: ```text 📎 example.pdf ``` Поля: - `id` — `Base58(SHA-256(ciphertext))`; - `url` — абсолютный URL ciphertext на access-сервере отправителя, percent-encoded; - `key` — случайный 32-byte AES-256 key в Base64URL; - `iv` — случайный 12-byte AES-GCM IV в Base64URL; - `name` — исходное безопасно нормализованное имя файла, percent-encoded; - `mime` — исходный MIME, percent-encoded; - `size` — размер plaintext в байтах; - `encsize` — размер ciphertext в байтах. `key`, `iv` и метаданные безопасно находятся здесь только потому, что весь plaintext DM затем шифруется существующим E2EE-механизмом. Они не передаются файловому HTTP endpoint отдельно. Текст `📎 example.pdf` после блока служит fallback для старого клиента. Новый официальный UI вместо него рисует карточку файла и кнопку «Скачать». Перед локальной AES-GCM-расшифровкой клиент обязан повторно вычислить SHA-256 скачанного ciphertext и сравнить Base58 с `id`. ## 8. Поведение официального UI Официальный UI SHiNE в v1: - скрывает все корректные `` и legacy `` блоки в начале plaintext; - для `call` строит специальный человекочитаемый текст: - `Звонок: M:SS` - `Звонок: H:MM:SS` - `Звонил, но недозвонился: ...` - для `reply` скрывает сам блок и показывает только текст ответа; - для `file` скрывает fallback-текст и показывает карточку вложения с локальным download/decrypt; - если исходное reply-сообщение не найдено, reply-preview не показывается. ## 9. Совместимость Так как это часть plaintext, а не часть серверного envelope: - сервер не обязан понимать этот формат; - будущие клиенты могут добавлять новые `kind`; - клиенты, которые распознают SHiNE-вставки, должны скрывать неизвестные блоки целиком, если они стоят в начале и корректно закрыты. ## 10. Расширение `file` v2 Клиент обязан продолжать читать `v=1`. Новые chunked-вложения отправляются так: ```text ``` Дополнительные поля v2: - `id` / `url` указывают не на весь файл, а на зашифрованный root manifest; - `ivp` — случайный 4-byte IV prefix, из которого детерминированно строятся уникальные IV chunks/pages/root; - `chunk` — plaintext chunk size, сейчас `1048576`; - `chunks` — число частей; - `th` — BitTorrent v2 SHA-256 infohash; - `pr` — BitTorrent v2 pieces root; - `kind=file|voice`; - `dur` — длительность voice в миллисекундах, для обычного файла `0`. В одном plaintext DM разрешено несколько последовательных `` блоков. Официальный UI собирает их в один список вложений и скрывает fallback-текст. Подробный формат chunk encryption, manifest pages и BitTorrent v2 hashing: `Файлы_DM_v2.md`.