wt 25a3fb9dd3
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
Update packs.yml
2026-08-11 16:04:59 +07:00
2026-08-11 16:04:59 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-08-10 17:55:37 +07:00
2026-07-30 20:36:49 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-08-11 15:42:01 +07:00
2026-08-11 15:42:01 +07:00
2026-07-30 20:36:49 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00
2026-07-30 20:07:51 +07:00

Luma

Luma — рабочий MVP XMPP-клиента для iOS, iPadOS, macOS и Apple Watch с интерфейсом в духе Telegram/iMessage. Клиент не привязан к одному провайдеру: он подключается к обычному XMPP-серверу по JID, включая Prosody.

Что уже реализовано

  • вход по JID и паролю; пароль хранится в Apple Keychain;
  • DNS SRV, STARTTLS и direct TLS, а также ручной host/port;
  • roster, presence, личные чаты и групповые комнаты XEP-0045 (MUC), включая создание/вход, приглашения, автоподключение и число участников;
  • отдельный раздел «Контакты»: люди синхронизируются с roster Prosody, а рядом показываются сохранённые MUC-комнаты; есть общий поиск, аватары и статусы;
  • OMEMO для исходящих и входящих сообщений в личных и неанонимных MUC-чатах, постоянные ключи, TOFU и ручная проверка отпечатков устройств;
  • глобальный переключатель OMEMO и отдельный режим для каждого чата: наследовать глобальную настройку, всегда шифровать или отправлять без OMEMO;
  • XEP-0198 Stream Management, XEP-0280 Message Carbons и XEP-0313 MAM;
  • delivery receipts и локальная история;
  • редактирование текстовых сообщений через XEP-0308, включая исправления в OMEMO-чатах и синхронизацию через Carbons/MAM;
  • ответы через XEP-0461 и XEP-0428: Luma показывает исходное сообщение уменьшенным полупрозрачным bubble с дугой и открывает по нажатию фокус-режим всей ветки в стиле iMessage; текстовые >-цитаты старых Conversations/Monal также разбираются, а в MUC используется выданный комнатой stanza-id;
  • пересылка текста, геопозиции и медиа в существующий чат или на введённый JID; через пункт «Выбрать» можно отметить несколько сообщений и переслать их в исходном порядке; медиа скачивается/расшифровывается и загружается заново для получателя;
  • «Удалить у всех» через XEP-0424 Message Retraction с tombstone в истории и отдельное постоянное «Удалить у меня», которое не возвращает сообщение после очередной синхронизации MAM; оба действия поддерживают несколько выбранных сообщений;
  • съёмка фото прямо системной камерой iPhone, а также выбор фото и видео из медиатеки; фото, видео, музыка и файлы отправляются через XEP-0363 HTTP File Upload; при включённом OMEMO содержимое шифруется до загрузки, а исходное расширение имени сохраняется для совместимости с Conversations и Monal;
  • множественный выбор до 20 фото/видео или файлов, полноэкранный предпросмотр фото и воспроизведение видео до отправки, удаление отдельных элементов и подпись; после сетевой ошибки неотправленные файлы остаются для повторной попытки, а параллельные загрузки не могут оставить интерфейс заблокированным;
  • фото и видео показывают inline-превью и по нажатию открываются поверх всего окна приложения; полноэкранный просмотр закрывается вертикальным свайпом без отдельного крестика, увеличенное фото продолжает свободно перемещаться внутри, а видео использует системные элементы воспроизведения; музыка получает inline-плеер с названием файла, длительностью и перемоткой;
  • каждое фото и видео помещается в отдельный скруглённый островок с внутренним отступом и aspectFit: миниатюра не обрезается, не выходит за границы и не слипается с соседними вложениями;
  • запись голосовых сообщений и круглых видеосообщений (до 60 секунд) с камеры; голосовые показывают waveform, поддерживают паузу, перемотку и скорости 1×/1.5×/2×, а видеосообщения воспроизводятся прямо в круглом bubble, который слегка увеличивается на время воспроизведения;
  • явно видимый пункт «Отправить геопозицию» в меню +, выбор текущей или произвольной точки на карте и отправка стандартного geo: URI, распознаваемого другими XMPP-клиентами;
  • аватары контактов и обновление собственного аватара через XEP-0084 PEP с совместимым fallback на vCard-temp;
  • личные аудио- и видеозвонки через XMPP Jingle (XEP-0166/XEP-0167), ICE-UDP/DTLS-SRTP и WebRTC; есть входящий экран, mute, динамик, камера и её переключение, а STUN/TURN автоматически берутся через XEP-0215; некорректные ICE-записи от сервера отбрасываются, затем используются публичный STUN и прямые host candidates, поэтому они не блокируют запуск media engine; исходящий session-accept нормализуется по порядку media-линий offer; Jingle Message Initiation сразу адресуется выбранному по presence/caps full JID; trickle ICE ждёт удалённый SDP, но больше не зависает в ожидании ресурса, поэтому transport-info не попадает на другой endpoint и не остаётся в очереди до timeout;
  • завершённые аудио- и видеозвонки показываются в истории чата отдельными Telegram-подобными карточками: входящий/исходящий, длительность, отклонённый, пропущенный, отменённый, без ответа или неудачный; пропущенный входящий помечает чат непрочитанным;
  • у обычных текстовых и файловых сообщений используются чистые скруглённые островки без «хвостиков»;
  • единый заполненный AppAssets.xcassets/AppIcon со всеми 42 размерами для iPhone, iPad, Mac и Apple Watch; один и тот же catalog явно подключён ко всем app-target’ам, а имя закреплено в build settings и Info.plist;
  • адаптивный SwiftUI-интерфейс для iPhone, iPad и Mac;
  • companion-приложение watchOS: последние чаты, диктовка/ответы, а также запись голосового до 60 секунд с отменой и предпрослушиванием; .m4a передаётся на iPhone фоновой файловой очередью WatchConnectivity, после чего iPhone отправляет его через обычный XEP-0363/OMEMO media-пайплайн и возвращает часам итоговый статус; это современный single-target watchOS app, поэтому SwiftUI-код и executable собираются в одном target без устаревшего WatchKit App/Extension контейнера;
  • системные уведомления для новых сообщений, пока приложение запущено в фоне или на экране; в открытом сейчас диалоге дублирующий banner не показывается.

Сборка

Нужны macOS, Xcode 16 или новее и XcodeGen.

brew install xcodegen
cd Luma
make project
open Luma.xcodeproj

После обновления архива обязательно снова выполните make project: новые build settings AppIcon берутся из project.yml. Если устройство или Simulator закэшировали старую пустую иконку, один раз удалите установленную Luma и установите её заново; на macOS после новой сборки перезапустите Dock или сам Mac. Можно вместо команд дважды нажать Regenerate-Luma-Project.command в корне проекта (XcodeGen всё равно должен быть установлен). При переходе с версии 0.8.7 один раз выполните в Xcode Product → Clean Build Folder, чтобы удалить кэш старого application.watchapp2 target.

После открытия проекта:

  1. Выберите свою Apple Development Team для Luma, LumaMac и LumaWatch.
  2. При необходимости замените bundle identifiers app.luma.chat* в project.yml на уникальные.
  3. Дождитесь загрузки Swift packages.
  4. Запустите scheme Luma на iPhone/iPad или LumaMac на Mac.

Для проверки из терминала на Mac:

make verify

Версии Martin, MartinOMEMO и WebRTC закреплены в project.yml. Зависимости Martin имеют copyleft-лицензии, поэтому Luma распространяется под AGPL-3.0-or-later.

Prosody

Минимально нужны pep, smacks, carbons, mam и MUC component. pep используется и для OMEMO, и для XEP-0084 аватаров. Для медиа и вложений добавьте компонент http_file_share; для надёжных звонков за NAT — coturn и turn_external. Готовый пример и команды проверки находятся в Docs/PROSODY.md.

Важные границы MVP

  • OMEMO-модуль использует широко развёрнутый профиль с namespace eu.siacs.conversations.axolotl, совместимый со многими версиями Monal и Conversations. Поддержку нового namespace urn:xmpp:omemo:2 следует добавить отдельным криптографическим адаптером до объявления полной совместимости с актуальным XEP-0384.
  • Надёжный push при выгруженном iOS-приложении не может работать только через XMPP-сокет. Для production нужны Apple Developer credentials, APNs provider, XEP-0357 push-компонент и регистрация приложения в этом компоненте.
  • При первом запуске Luma запрашивает ограниченную последнюю страницу серверного MAM-архива, чтобы огромная история не блокировала интерфейс. После успешного прохода сохраняются серверный UID последней записи и время; следующие подключения продолжают RSM строго после UID. Временное перекрытие используется только для старых snapshots без UID или один раз, если сервер удалил сохранённый UID. Сырые stanza собираются вне main queue, расшифровываются по одной с уступкой UI, а готовый проход публикуется одной пачкой. Один foreground-проход также ограничен по страницам и времени; после ошибки он не перезапускает сам себя бесконечно.
  • Клиент не вводит собственного ограничения размера вложения: фактический предел сообщает XEP-0363 upload-компонент сервера. Видеосообщение ограничено 60 секундами.
  • XEP-0424 retract является запросом на удаление: федеративный XMPP не может гарантировать стирание уже полученной или скопированной версии в чужом клиенте. «Удалить у меня» влияет только на это устройство.
  • Групповое OMEMO требует неанонимную MUC-комнату и OMEMO-устройство у каждого получателя. Luma создаёт новые комнаты members-only/persistent с muc#roomconfig_whois=anyone; для несовместимой чужой комнаты безопасная отправка блокируется без автоматического перехода на plaintext. Сервер также должен разрешать участникам читать списки member/admin/owner.
  • Звонки в MVP работают один-на-один, пока приложение запущено и XMPP-соединение активно. WebRTC защищает медиапоток DTLS-SRTP, но это отдельный механизм от OMEMO. Для надёжного входящего звонка после выгрузки iOS-приложения нужны PushKit/CallKit, APNs provider и серверный push-компонент. Карточка звонка хранится в локальной истории участвовавшего устройства Luma; она не отправляется собеседнику как фальшивое текстовое сообщение и поэтому не синхронизируется через MAM.
  • Реакции и групповые звонки относятся к следующему этапу.

Архитектура описана в Docs/ARCHITECTURE.md, модель угроз и ограничения хранения — в Docs/SECURITY.md.

S
Description
modern XMPP-client application
Readme AGPL-3.0
5.5 MiB
0.10.6
Latest
2026-07-30 20:10:01 +07:00
Languages
Swift 96.8%
Shell 3.2%