You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4.7 KiB

DM — прямой p2p чат между двумя пользователями группы

1. Цель

Возможность начать личный чат с любым пользователем доступных групп. Пока target offline сообщения временно хранятся на storage-узлах.

2. Ключевые решения

  • Отдельная DM-подсистема (НЕ канал: без TOPO_GROUP/member_sync/merkle).
  • Идентичность детерминированная: одна ветка на пару, согласование без handshake.
  • E2E-шифрование содержимого сразу.
  • Offline-хранение: dm_mailbox на storage-узлах с флагом dm_storage.
  • Доставка: fallback — сперва проверка наличия узла в BGP-группе; доступен → прямой send; нет связи → storage.

3. Идентичность и ключи (детерминированные)

conv_id     = SHA256("utun_dm_v1" || min(node_a,node_b) || max(node_a,node_b))[..63]
shared      = X25519(my_x25519_priv, peer_x25519_pub)
content_key = SHA256(shared || "utun_dm_content")

Обе стороны выводят одинаковые значения из своего privkey и pubkey пира (известен из общей группы). Смена x25519 у пира = новая ветка.

4. Модель данных (SQLite, общий chats.db)

dm_conversations(conv_id TEXT PK, peer_node_id, peer_x25519 BLOB, peer_ed25519 BLOB,
                 peer_name TEXT, last_out_seq INT, last_in_seq INT, created_at INT, last_ts INT)
dm_messages(conv_id TEXT, dir INT, seq INT, ts INT, author INT, ct TEXT,
            data BLOB, sig BLOB, PRIMARY KEY(conv_id,dir,seq))
dm_mail(recipient INT, sender INT, conv_id TEXT, seq INT, ts INT, data BLOB, sig BLOB,
        ttl INT, PRIMARY KEY(recipient,sender,seq))

Два независимых направленных потока (A→B, B→A) с монотонным seq. Без chain-хеша: для 2 пиров достаточно seq + catch-up по диапазону.

5. Доставка

  1. Проверка доступности: peer присутствует в BGP-группе (общая группа).
  2. Доступен → прямой send (сервис ETCP_RT_ID_DM = 0x34), ждём DM_ACK{conv_id,seq}. Нет ACK за таймаут → fallback в mailbox.
  3. Нет связи → MAIL_PUT на 1..N storage-узлов.
  4. Catch-up при connect: DM_HELLO{conv_id,last_out_seq,last_in_seq} → пир досылает (in_seq+1 .. out_seq).
  5. Dedup: вставка только при seq > last_in_seq.

6. E2E-шифрование

data_enc = nonce(13B, счётчик по seq) || AES-CCM_ct || tag

secure_channel уже умеет AES-CCM. Storage/relay видят только шифротекст.

7. Storage-узлы (dm_storage)

  • Новый флаг dm_storage=yes в adm_tags (блок B владельца), распространяется существующим member_sync без нового синка.

  • DM читает adm_tags мемберов общих групп (peers_) и кэширует storage-узлы.

  • Протокол mailbox (сервис ETCP_RT_ID_DM_MAILBOX = 0x35):

    MAIL_PUT {recipient,sender,conv_id,seq,ts,data,sig}
    MAIL_PULL {recipient, per-sender cursor}
    MAIL_ACK {up_to_seq}
    

    TTL 7 дней + лимит объёма, dedup по (recipient,sender,seq).

8. Старт и anti-spam

  • dm_start(peer): создать беседу (вывести conv_id/ключи), обеспечить прямое соединение (переиспользовать chat_sync_connect_node/node_conn_direct).
  • Пир автопринимает на первом DM_HELLO/сообщении, только если отправитель в общей группе.

9. Файлы и интеграция

Файл Назначение
src/dm/dm_core.c/h беседы, send/recv, таблицы, bind 0x34, conn-события, fallback
src/dm/dm_crypto.c/h derive + AES-CCM
src/dm/dm_mailbox.c/h storage-узел, push/pull/ack, bind 0x35

Плюс:

  • src/chat/chat_member.c — бит CHAT_MEMBER_FLAG_DM_STORAGE + парсинг dm_storage.
  • utun_instance.c — dm_core_init/destroy.
  • chat_core — API dm_start/send/list + события CHAT_EVT_DM_*.
  • headless CLI — dm list/send/messages.
  • src/Makefile.am — новые источники.

10. Сервисы ETCP

ETCP_RT_ID_DM         = 0x34
ETCP_RT_ID_DM_MAILBOX = 0x35