79 lines
12 KiB
Plaintext
79 lines
12 KiB
Plaintext
Внедрение группы устройств в чат (devgroup).
|
||
|
||
Первый этап: объединение устройств одного пользователя и группировка в списке участников.
|
||
|
||
1. Идентичность и хранение.
|
||
Устройство состоит максимум в одной devgroup. При создании группы генерируются две отдельные общие пары ключей:
|
||
X25519 для шифрования и Ed25519 для подписей. Публичный ключ Ed25519 идентифицирует группу.
|
||
Обе пары одинаковы на всех устройствах devgroup; при добавлении устройств передаются существующие ключи.
|
||
Принадлежность подтверждает подпись devgroup над идентичностью конкретного устройства (node_id и его публичные ключи).
|
||
Одного совпадения публичного ключа devgroup недостаточно.
|
||
Публичные данные devgroup хранятся в отдельных полях nodes: оба публичных ключа, удостоверение устройства, JSON профиля и его подпись.
|
||
Эти же данные входят в TOPO_NODE и подписанный снимок node_snapshots; nodes содержит их согласованную проекцию.
|
||
Принадлежность общая для узла, независимо от каналов; в peers_<channel_id> и userinfo поля devgroup не добавляются.
|
||
Секреты хранятся отдельно от публичного профиля и не теряются при перезапуске; текущий local_identity перезаписывается при старте.
|
||
|
||
2. Приглашение.
|
||
A выбирает «Это моё устройство» в контекстном меню B. Пункт виден только для неудалённого чужого устройства
|
||
без devgroup, доступного через живой BGP-маршрут. На Android меню доступно по ⋮ и долгому нажатию строки.
|
||
Сначала открывается пояснение об общей подгруппе/ключах и PIN. Только кнопка «Связать» начинает приглашение;
|
||
до отправки повторно проверяются выбранный канал, доступность B и отсутствие у B подгруппы.
|
||
На A показывается PIN из 4 цифр. На B запрос не открывает окно: в меню self (либо своей подгруппы)
|
||
появляется «Завершить спаривание». На Android этот пункт доступен по ⋮ и долгому нажатию.
|
||
Открытое пользователем окно объясняет операцию и предлагает просто закрыть его, если пользователь не связывает личные устройства.
|
||
Закрытие окна не принимает приглашение; до истечения срока его можно снова открыть из меню self.
|
||
B вводит PIN с экрана A и генерирует отдельный ответный PIN, отличный от введённого.
|
||
После проверки первого PIN на A появляется ввод ответного PIN с экрана B.
|
||
Ответный PIN не передаётся автоматически: A отправляет только введённую пользователем попытку, которую проверяет B.
|
||
До успешной проверки обоих PIN ключи не передаются; B принимает ключи только после проверки своего ответного PIN.
|
||
Обмен идёт через ETCP-router с обязательными сквозным шифрованием и подписью; BGP обеспечивает маршрут.
|
||
Приглашение одноразовое, привязано к ключам B и случайному ID, действует 2 минуты на оба шага, допускает по 3 попытки каждого PIN.
|
||
Только после успешной проверки обоих PIN A создаёт обе пары ключей, если группы ещё нет; иначе использует существующие.
|
||
A передаёт ключи и профиль группы. B проверяет и сохраняет их, затем подтверждает успех.
|
||
Повторы идемпотентны; потеря подтверждения означает неизвестный результат, а не отказ. Переданные секреты отменой не отзываются.
|
||
Устройство из другой devgroup должно сначала выйти из неё; неявного слияния групп нет.
|
||
|
||
3. Профиль и версии.
|
||
Ник, ver, timestamp и публичный ключ X25519 входят в расширяемый JSON, целиком подписанный ключом Ed25519 devgroup
|
||
с отдельным назначением подписи. Подпись связывает ключ шифрования с идентичностью группы.
|
||
Хранятся и пересылаются исходные подписанные байты. Победитель определяется по (ver, timestamp, SHA256(JSON)).
|
||
Локальное изменение увеличивает максимальную известную ver на 1; при репликации версия не увеличивается.
|
||
Для профиля devgroup задаётся отдельный ограниченный размер с учётом полного NODEINFO; лимит userinfo менять не требуется.
|
||
Версия профиля devgroup и timestamp подписанного снимка узла независимы.
|
||
|
||
4. Репликация первого этапа.
|
||
Данные devgroup распространяются через текущую синхронизацию nodes (NODEINFO/BGP) в составе общей подписанной записи узла.
|
||
Текущих гарантий доставки достаточно для первого этапа; отдельный протокол синхронизации и offline-доставки не добавляется.
|
||
Проверяются подпись узла, удостоверение принадлежности и подпись профиля devgroup. Обновление снимка заменяет блок целиком.
|
||
Более свежий профиль своей devgroup устройство принимает и публикует в новом собственном снимке во всех своих топологических группах.
|
||
Чужие снимки не меняются; неизменившийся профиль не вызывает новой публикации.
|
||
Синхронизация зависит от распространения NODEINFO через существующие группы; отдельная сеть устройств в первый этап не входит.
|
||
После восстановления связи и при вступлении в новую группу используется штатный обмен NODEINFO.
|
||
|
||
5. Выход.
|
||
Кнопка «Отключить от моих устройств» доступна в свойствах self. Выход удаляет локальные ключи и публикует новый собственный снимок с пустым блоком devgroup и увеличенным timestamp.
|
||
Локальное состояние, снимок node_snapshots и поля nodes меняются атомарно; уведомления и распространение выполняются после commit.
|
||
Старые сетевые записи не возвращают устройство в группу. Принудительный отзыв устройства со сменой ключей — отдельный этап.
|
||
|
||
6. Список участников и границы этапа.
|
||
В Qt и Android устройства с проверенной принадлежностью объединяются под раскрывающимся [+] с актуальным ником devgroup.
|
||
Принадлежность берётся из nodes по node_id; профиль выбирается простым поиском наиболее свежего проверенного объявления
|
||
среди текущих записей известных узлов devgroup по порядку из п. 3. Отдельный постоянный кеш профилей не нужен.
|
||
Изменение общей записи обновляет отображение участника во всех каналах, где он присутствует.
|
||
Внутри показываются устройства текущего канала. Права и действия остаются у конкретных устройств;
|
||
заголовок группы не подменяется node_id одного из них. Группа online, если доступно хотя бы одно активное устройство.
|
||
Звонки на все устройства и объединение DM в первый этап не входят.
|
||
|
||
Порядок реализации: nodes/TOPO_NODE/снимок и проверка devgroup → NODEINFO/BGP и профиль → приглашения → API/headless → Qt и Android.
|
||
Проверить подделки, конфликты версий, обновление через штатный обмен NODEINFO, повторы, потери ответов, перезапуск, ошибки сохранения и выход.
|
||
Логи показывают состояния и причины отказов, но не PIN и секреты.
|
||
|
||
Протокол приглашений (все сообщения signed+encrypted, общий заголовок kind1,id16):
|
||
OFFER=1 без тела; PIN=2 и RETURN_PIN=5: attempt1,PIN4; KEYS=3: ed_priv32,x_priv32,record;
|
||
RESULT=4: phase1,attempt1,result1. phase:1=первый PIN,2=ответный PIN,3=импорт; result:0=успех,1=повтор ввода,2=отказ.
|
||
Каждый счётчик попытки принимается один раз; сетевой повтор с тем же PIN возвращает прежний результат, с иным отвергается.
|
||
Состояния UI:1=ожидается первый PIN,2=проверка первого,3=отправлены ключи,4=успех,5=отказ,6=истёк,
|
||
7=результат неизвестен,8=ожидается ответный PIN,9=его проверка,10=B ожидает ключи после проверки ответного PIN.
|
||
Локальный status JSON содержит показываемый собственный PIN, input=1/2 для ввода и pin_error для повторной попытки.
|
||
Этот JSON предназначен только для локального UI/control API и не логируется; введённые PIN в снимок не попадают.
|