SHA256
Реализовать SHiNE_DM v1 с E2EE и tombstone
This commit is contained in:
@@ -61,6 +61,8 @@
|
||||
| `SendMessagePair` | `12_Direct_Messages_Push_Calls_API.md` | отправка пары входящий/исходящий DM |
|
||||
| `ReceiveOutcomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | алиас `SendMessagePair` |
|
||||
| `ReceiveIncomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | прием входящего DM-блока |
|
||||
| `DeleteMessage` | `12_Direct_Messages_Push_Calls_API.md` | tombstone одного личного сообщения у обеих сторон |
|
||||
| `DeleteConversation` | `12_Direct_Messages_Push_Calls_API.md` | tombstone удаления истории переписки |
|
||||
| `AckSessionDelivery` | `12_Direct_Messages_Push_Calls_API.md` | подтверждение доставки в сессию |
|
||||
| `CallInviteBroadcast` | `12_Direct_Messages_Push_Calls_API.md` | broadcast приглашения к звонку |
|
||||
| `CallSignalToSession` | `12_Direct_Messages_Push_Calls_API.md` | сигнал звонка в конкретную сессию |
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
- `incomingBlobB64` — блок `type=1` или `type=3`
|
||||
- `outgoingBlobB64` — блок `type=2` или `type=4`
|
||||
|
||||
Для контентных сообщений `type=1/2` внутри base64 лежит бинарный формат `SHiNE_DM`.
|
||||
Все типы в этой паре используют бинарный формат `SHiNE_DM`.
|
||||
|
||||
### Запрос
|
||||
|
||||
@@ -110,8 +110,7 @@
|
||||
|
||||
- `400 / BAD_FIELDS` — пустой `incomingBlobB64` или `outgoingBlobB64`
|
||||
- `400 / BAD_BLOCK_FORMAT` — base64 или бинарный контейнер повреждён
|
||||
- `400 / BAD_CONTENT_FORMAT` — для контентного сообщения пришёл не `SHiNE_DM`
|
||||
- `400 / ATTACHMENTS_DISABLED` — в `SHiNE_DM` пришёл `attachmentsCount != 0`
|
||||
- `400 / BAD_CRYPTO_METHOD` — неподдерживаемый метод шифрования контейнера `EncryptedBody_v1_0`
|
||||
- `404 / USER_NOT_FOUND` — один из логинов не найден
|
||||
- `460 / BAD_SIGNATURE` — подпись блока не прошла проверку
|
||||
|
||||
@@ -123,6 +122,11 @@
|
||||
|
||||
Используется там, где нужно принять только incoming-вариант сообщения.
|
||||
|
||||
Принимаемые типы:
|
||||
|
||||
- `type=1` — входящая копия сообщения
|
||||
- `type=3` — входящий read-receipt
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
@@ -135,7 +139,39 @@
|
||||
}
|
||||
```
|
||||
|
||||
## 5. `AckSessionDelivery`
|
||||
## 5. `DeleteMessage`
|
||||
|
||||
Принимает один signed DM-блок `type=5` или `type=6`.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "DeleteMessage",
|
||||
"requestId": "dm-del-001",
|
||||
"payload": {
|
||||
"blobB64": "BASE64_DELETE_BLOCK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. `DeleteConversation`
|
||||
|
||||
Принимает один signed DM-блок `type=7` или `type=8`.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "DeleteConversation",
|
||||
"requestId": "dm-del-all-001",
|
||||
"payload": {
|
||||
"blobB64": "BASE64_DELETE_CONVERSATION_BLOCK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. `AckSessionDelivery`
|
||||
|
||||
Требует авторизации. Подтверждает доставку в текущую сессию.
|
||||
|
||||
@@ -151,7 +187,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Событие `SignedMessageArrived`
|
||||
## 8. Событие `SignedMessageArrived`
|
||||
|
||||
Сервер присылает его по WebSocket в активные сессии адресата.
|
||||
|
||||
@@ -174,18 +210,19 @@
|
||||
|
||||
Если это новая ревизия того же письма, `messageKey` остаётся тем же, а `revisionTimeMs` меняется внутри бинарного блока.
|
||||
|
||||
## 7. `CallInviteBroadcast`
|
||||
Для типов `5/6/7/8` событие тоже приходит в таком же конверте, но логика применения определяется `messageType` и бинарным `blobB64`.
|
||||
|
||||
## 9. `CallInviteBroadcast`
|
||||
|
||||
Требует авторизации. Шлёт приглашение к звонку в активные сессии `toLogin`.
|
||||
|
||||
## 8. `CallSignalToSession`
|
||||
## 10. `CallSignalToSession`
|
||||
|
||||
Требует авторизации. Шлёт сигнал звонка в конкретную сессию.
|
||||
|
||||
## 9. Замечания
|
||||
## 11. Замечания
|
||||
|
||||
- read-receipt `type=3/4` пока остаются в legacy-формате `SHiNE_dm2`
|
||||
- контентные DM `type=1/2` используют `SHiNE_DM`
|
||||
- сервер хранит только последнюю версию контентного сообщения по `messageKey`
|
||||
- удаление сообщения реализуется новой ревизией с пустым телом и `attachmentsCount = 0`
|
||||
- все DM-типы `1..8` используют `SHiNE_DM`
|
||||
- сервер не расшифровывает DM и не использует ciphertext как preview текста
|
||||
- сервер хранит последнюю применённую ревизию контентного сообщения и отдельные tombstone-события удаления
|
||||
- HTTP endpoints для DM-файлов сейчас отсутствуют
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# DM v1: E2EE, tombstone и fan-out
|
||||
|
||||
- краткое описание фичи:
|
||||
Новый протокол личных сообщений `SHiNE_DM` v1: реальные зашифрованные тела `X25519 + HKDF-SHA256 + AES-256-GCM`, read-receipt в том же контейнере, удаление одного сообщения, удаление истории переписки и межсерверная доставка по `access_servers`.
|
||||
|
||||
- что именно проверять:
|
||||
1. Отправка нового DM между двумя пользователями и чтение текста на стороне получателя.
|
||||
2. Отправка/чтение своей исходящей копии у отправителя.
|
||||
3. Редактирование сообщения с тем же `baseKey` и ростом `revisionTimeMs`.
|
||||
4. Подтверждение прочтения `type=3/4`.
|
||||
5. Удаление исходящего сообщения отправителем (`type=5`) и удаление входящего сообщения получателем (`type=6`).
|
||||
6. Удаление истории переписки (`type=7/8`) и игнорирование более старых сообщений после tombstone.
|
||||
7. Сценарий с несколькими `access_servers`, включая случай общего сервера у обеих сторон.
|
||||
|
||||
- ожидаемый результат:
|
||||
Сообщения шифруются и расшифровываются только на клиенте, сервер не показывает plaintext из ciphertext, старые ревизии не оживают после tombstone, общие серверы не получают лишних дублей пары, а удаление и read-receipt корректно доходят обеим сторонам.
|
||||
|
||||
- статус:
|
||||
pending
|
||||
@@ -0,0 +1,17 @@
|
||||
# Личные сообщения SHiNE
|
||||
|
||||
Эта папка содержит актуальную документацию по личным сообщениям SHiNE.
|
||||
|
||||
Точка входа:
|
||||
|
||||
- `Dev_Docs/Personal_Messages/Протокол_DM_v1.md` — логика протокола, роли API, серверное поведение, routing по `access_servers`
|
||||
- `Dev_Docs/Personal_Messages/Формат_DM_v1.md` — точный бинарный формат контейнера `SHiNE_DM`
|
||||
|
||||
Исторический устаревший документ сохранён отдельно:
|
||||
|
||||
- `Dev_Docs/Personal_Messages/Спецификация_DM_v0.5_устаревшая.md`
|
||||
|
||||
Правило сопровождения:
|
||||
|
||||
- код DM и оба документа `Протокол_DM_v1.md` + `Формат_DM_v1.md` всегда должны обновляться синхронно;
|
||||
- если меняется поведение DM в коде, в том же наборе изменений обновляется и эта документация.
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
## Статус документа
|
||||
|
||||
Этот файл — актуальная логическая спецификация DM-протокола SHiNE следующего этапа.
|
||||
Этот файл — актуальная логическая спецификация DM-протокола SHiNE v1.
|
||||
|
||||
Важно:
|
||||
|
||||
- это целевая спецификация;
|
||||
- в текущем коде она ещё реализована не полностью;
|
||||
- при реализации код должен приводиться именно к этой спецификации, а не наоборот.
|
||||
- это актуальная реализованная спецификация;
|
||||
- код и документы по DM должны изменяться синхронно;
|
||||
- при любых будущих изменениях DM сначала обновляется эта спецификация и соседний документ формата.
|
||||
|
||||
Документ фиксирует:
|
||||
|
||||
@@ -151,7 +151,6 @@
|
||||
|
||||
- новые входящие сообщения;
|
||||
- входящие обновления/редактирования;
|
||||
- входящие служебные события удаления;
|
||||
- будущие входящие перешифрованные копии.
|
||||
|
||||
## 5. Удаление одного сообщения
|
||||
@@ -286,7 +285,7 @@
|
||||
Их роли в v1:
|
||||
|
||||
- `SendMessagePair` — новая пара сообщений и редактирование старой пары автором;
|
||||
- `ReceiveIncomingMessage` — приём одной входящей копии, входящих редактирований и служебных DM-событий;
|
||||
- `ReceiveIncomingMessage` — приём одной входящей копии, входящих редактирований и входящего read-receipt;
|
||||
- `ReceiveOutcomingMessage` — алиас `SendMessagePair`.
|
||||
|
||||
### 8.2. Новые методы, которые нужны
|
||||
@@ -399,7 +398,6 @@ Request:
|
||||
|
||||
- приём одной входящей копии по схеме server-to-server;
|
||||
- приём входящего редактирования;
|
||||
- приём служебного входящего события удаления;
|
||||
- приём входящего read-receipt.
|
||||
|
||||
Request:
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
Важно:
|
||||
|
||||
- это целевой формат следующего этапа;
|
||||
- в текущем коде он ещё реализован не полностью;
|
||||
- особенно это касается перехода всех типов `1..8` на единый контейнер `SHiNE_DM`.
|
||||
- это актуальный формат, реализованный в текущем коде;
|
||||
- контейнер `SHiNE_DM` используется для всех типов `1..8`;
|
||||
- при любых будущих изменениях DM этот документ обновляется одновременно с кодом.
|
||||
|
||||
Логика протокола, API и поведение сервера описаны отдельно:
|
||||
|
||||
@@ -156,6 +156,19 @@ Nonce/IV для `AES-GCM`.
|
||||
|
||||
Сервер не должен трактовать это поле как UTF-8 текст и не должен пытаться расшифровывать его в обычной DM-логике.
|
||||
|
||||
### Точная схема для `cryptoMethod = 1`, `cryptoVersion = 0`
|
||||
|
||||
- публичный ключ получателя для E2EE получается как стандартное преобразование `Ed25519 -> X25519`;
|
||||
- отправитель генерирует ephemeral `X25519` приватный ключ и кладёт соответствующий `ephemeralPubKey` в контейнер;
|
||||
- общий секрет вычисляется как `X25519(ephemeralPrivKey, recipientX25519PubKey)`;
|
||||
- `HKDF-SHA256` использует:
|
||||
- `salt = ephemeralPubKey || recipientX25519PubKey`
|
||||
- `info = "SHiNE_DM|1|0|X25519+HKDF-SHA256+AES-256-GCM"` в ASCII
|
||||
- `outputLen = 32`
|
||||
- полученные `32` байта используются как ключ `AES-256-GCM`;
|
||||
- поле `cipherText` хранит стандартный результат библиотеки `AES-GCM` в виде:
|
||||
- `ciphertext || tag`
|
||||
|
||||
## 6. Поле `body` для типов `3/4`
|
||||
|
||||
Для read-receipt типов `3/4` поле `body` содержит открытый контейнер ссылки на исходное сообщение:
|
||||
@@ -291,8 +304,6 @@ ReadReceiptBody_v1_0
|
||||
- ciphertext может различаться;
|
||||
- `reencryptedAtMs` при одной парной ревизии тоже должен совпадать.
|
||||
|
||||
## 13. Примечание о текущем коде
|
||||
## 13. Примечание о поддержке
|
||||
|
||||
В текущем коде типы `3/4` пока ещё реализованы старым контейнером `SHiNE_dm2`.
|
||||
|
||||
Для версии протокола v1 целевой формат фиксируется уже как единый `SHiNE_DM` для всех типов `1..8`.
|
||||
В версии DM v1 все типы `1..8` используют единый контейнер `SHiNE_DM`.
|
||||
|
||||
Reference in New Issue
Block a user