Задача и мой вклад
Смена телефона часто означает зависимость от номера, оператора аккаунта или отдельного резервного архива. Задача — дать человеку переносимый аккаунт и синхронизацию, не передавая серверу ключи от содержимого.
Мой вклад. Я определяю поведение аккаунта и восстановления, пользовательские сценарии, границы доверия между клиентом и сервером и конструкцию синхронизации. Отвечаю за то, чтобы техническая модель оставалась понятной человеку: что защищено, что видно серверу и что происходит при потере ключа.
Идентичность выводится из seed-фразы. Клиент шифрует записи до отправки, а сервер хранит зашифрованные сущности с ревизиями и курсорами. Локальная база служит проекцией для интерфейса. WebRTC-сигналинг отделён от хранения истории.
Что получилось
Доступен браузерный клиент. В исходниках реализованы переносимая идентичность, зашифрованная синхронизация аккаунта, ревизии, удаление через tombstone и проверка принадлежности профилю. Нативные сборки дополняют web локальным LAN-обменом. Демо ниже показывает реальный экран входа, а не испытание всей криптографической модели.
Инженерные решения
Повтор запроса без повтора изменения
Идемпотентные мутации и курсоры позволяют повторно доставить данные после обрыва связи. Подписанный запрос и его nonce решают отдельную задачу — защиту от повторного воспроизведения.
Удаление тоже синхронизируется
Tombstone сохраняет факт удаления. Иначе другой клиент может загрузить старую запись и вернуть уже удалённое сообщение.
История и соединение — разные сервисы
Сигналинг помогает установить связь между устройствами. Он не становится второй базой сообщений.
Архитектура
| Слой | Технологии и назначение |
|---|---|
| Frontend | React Native, Expo 55, TypeScript; web и нативные клиенты |
| Backend | Node.js, cloud-vault / sync, отдельный WebRTC-сигналинг |
| Данные | SQLite на клиенте; зашифрованные сущности, ревизии и курсоры на сервере |
| Безопасность | BIP39, did:key, @noble; ключи и шифрование на клиенте |
Компромиссы и выводы
Восстановление через seed-фразу убирает зависимость от номера телефона, но потерю фразы нельзя исправить сбросом пароля у оператора. Зашифрованные данные скрывают содержимое, но не все метаданные соединения и синхронизации.
Что показала практика
Ключевой риск синхронизации — локально успешное удаление, которое не переживает повторную загрузку истории. Поэтому удаление моделируется как состояние записи, а курсор двигается после применения изменений. Это описанный риск архитектуры, а не выдуманная история об инциденте.
Что бы я улучшил сейчас
Сейчас я бы прежде всего расширил воспроизводимые проверки на двух устройствах: конкурирующие изменения, удаление во время офлайна, восстановление и отзыв устройства. Результаты таких прогонов полезнее общего обещания «безопасного мессенджера».
Эксплуатация и данные
Синхронизация, сигналинг и уведомления разделены на самостоятельные сервисы. В исходниках предусмотрены scrubber логов и Sentry. Запуск нативного клиента требует соответствующей сборки и платформенных зависимостей; web имеет собственные ограничения.
Данные и миграции
У мутации есть идентификатор, ревизия, владелец и признак удаления. sync_entity_heads хранит локальные версии, sync_state — курсор и состояние синхронизации. Схема применяется на стороне соответствующего сервиса; это не одна общая база для всех клиентов.
| Сущность | Что хранится |
|---|---|
| Мутация | idempotency key, revision, owner, tombstone |
| sync_entity_heads | Локальная версия синхронизируемой записи |
| sync_state | epoch, pull cursor, timestamps |
| Медиа | Зашифрованные байты + ссылка; ключ у клиента |
Ограничения
Сервер видит метаданные. Посты по публичной ссылке не зашифрованы. Защита ключей в браузере слабее нативного secure storage. Для синхронизации и звонков нужна связь. Независимый аудит криптографической системы здесь не заявляется.
Проверяемые источники
Проверено 24.09.2026: 71 проверка sync/vault-сервиса; локальный /health отвечает. Это целевая проверка описанных решений, не аудит всего приложения.
Утверждения выше связаны с публичным кодом и документацией. Ссылки закреплены за проверенной версией; статус CI по ссылке может меняться.

