0.10.6
This commit is contained in:
commit
92660a4ba0
228 files changed
+24496
No files matched your search
@@ -0,0 +1,176 @@
|
||||
# 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.
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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`](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/ARCHITECTURE.md), модель
|
||||
угроз и ограничения хранения — в [`Docs/SECURITY.md`](Docs/SECURITY.md).
|
||||
Reference in new issue
Block a user