Files
xmpp-server-prosody/references/omemo-xep0384.md
T
2026-09-06 13:51:11 +00:00

4.9 KiB
Raw Blame History

OMEMO (XEP-0384) — проверка и публикация ключей (проверено 2026-08-28, nixg.ru)

Главное: серверный модуль НЕ нужен

OMEMO полностью работает на клиентах. Prosody хранит ключи/девайс-листы через PEP (pep в modules_enabled — уже включён). Если PEP включён — OMEMO работает для любого клиента (Gajim, Conversations, Dino, Converse). Серверного mod_omemo в prosody-modules НЕТ и он не нужен (это норма, не потеря).

Converse v14 (веб-чат)

  • OMEMO встроен: в dist лежат libomemo.esm.min.js + curve25519_compiled.wasm (проверить: grep -c omemo converse.min.js > 0, есть eu.siacs.conversations.axolotl).
  • ЕДИНСТВЕННАЯ опция в initialize(): omemo_default: true (default false) — «шифровать по умолчанию, когда контакт поддерживает». Опции allow_omemo в v14 нет (всегда доступен).
  • При логине с omemo_default:true Converse сам генерит device id и публикует devicelist + bundle в PEP. Проверять НЕ через UI — смотреть на диск.

Авторитетная проверка — файлы PEP на диске (host bigbox)

Каталог данных: data/ из docker-compose (в контейнере /var/lib/prosody), имена узлов URL-encoded:

  • devicelist: data/<domain-encoded>/pep_eu%2esiacs%2econversations%2eaxolotl%2edevicelist/admin.list → grep ["id"] = "N" — все устройства пользователя (например 4040, 14035).
  • bundle: data/<domain>/pep_eu%2esiacs%2econversations%2eaxolotl%2ebundles%3a<deviceid>/admin.list → должен содержать identityKey, 100× preKeyPublic (preKeyId 0..99), signedPreKeyPublic + signedPreKeySignature, имя bundle.
  • : nixg.ru → nixg%2eru (старый chin: chat%2enixg%2eru).

slixmpp 1.17: publish в PEP-узел (рабочий рецепт)

Подключение по WebSocket, паттерн 1.17 (нет .process(), connect возвращает Future):

import asyncio, ssl, slixmpp
from slixmpp.xmlstream import ET
ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
bot = slixmpp.ClientXMPP('user@domain', 'pass')
bot.ssl_context = ctx
bot.register_plugin('xep_0060')
bot.add_event_handler('session_start', ...)  # в handler: send_presence(); await get_roster()
fut = bot.connect(('wss://xmpp.example.com/xmpp-websocket',))
await asyncio.wait_for(fut, 20); await asyncio.sleep(6)  # дать событиям отработать

Publish (payload — СЫРОЙ lxml-элемент, не высокоуровневый API!):

lst = ET.Element('{eu.siacs.conversations.axolotl}list')
ET.SubElement(lst, '{eu.siacs.conversations.axolotl}device', {'id': '7777'})
await bot['xep_0060'].publish(jid=JID, node='eu.siacs.conversations.axolotl.devicelist',
                              id='current', payload=lst)

Засады:

  • iq['pubsub']['publish']['item']... + ElementBase.append('list', {'xmlns':...}) падает: TypeError: ElementBase.append() takes 2 positional arguments but 3 were given.
  • get_items может вернуть 0 items даже когда узел НЕ пуст (семантика доступа PEP) — диск admin.list авторитетнее. Проверять publish через чтение файла.

Проверка веб-клиента headless (camofox)

  • camofox-browser open https://chat... затем eval с JSON.stringify(...) — иначе возвращается только resultType, без значения.
  • Форма входа: input[name=jid], input[name=password], чекбокс trusted; submit-кнопка button.btn-primary (текст «Войти»). Заполнять через el.value=...; el.dispatchEvent(new Event('input',{bubbles:true})), потом click.
  • После входа в DOM: document.body.innerText содержит «Я на связи». В DOM появляется строка «OMEMO» (кнопка в чате).
  • Новый device от сессии виден в devicelist admin.list + каталог bundles:.

Очистка/удаление своего устройства из devicelist

Republish devicelist с оставшимися id (паттерн выше), id='current' — примет, тестовый id исчезает из admin.list.

Сопутствующее

  • omemo_default в доке Converse: https://conversejs.org/docs/configuration/ (redirect с /docs/html/...). Единственная omemo-опция.
  • Converse api.omemo недоступен из window.converse — проверять по диску, не по JS API.