finish SwiftData migration with @Query views
- Drive chat list, timeline and forward picker from SwiftData @Query instead of AppModel's in-memory arrays; inject the per-account ModelContext from RootView with an in-memory fallback. - Physically delete locally deleted messages (context.delete) and purge rows marked deleted by older builds on store open, so @Query views never resurrect them. - Delete the legacy JSON snapshot only after a successful import save and restore the completeUntilFirstUserAuthentication data protection attribute on the store file. - Mirror the old ChatArchive tolerant decoding in LegacyArchiveImporter so snapshots from older schema versions (missing reactions, isGroupMessage, roster fields) still import. - Cover the new behaviour in ArchiveStoreTests and guard it with new verify.sh invariants; update AGENTS.md, ARCHITECTURE.md and SECURITY.md.
This commit is contained in:
1 parent
277d8654c3
commit
2884810ec4
16 files changed
+653
-65
No files matched your search
@@ -9,7 +9,9 @@
|
||||
3. `LumaOMEMOStore` адаптирует постоянное состояние к Signal storage callbacks;
|
||||
AES-GCM выполняется CryptoKit.
|
||||
4. `AppModel` сводит сетевые события в UI-состояние, дедуплицирует MAM/live
|
||||
сообщения и сохраняет snapshot локально.
|
||||
сообщения и сохраняет их в per-account SwiftData-хранилище (`ArchiveStore`,
|
||||
отдельный `ModelContainer` на аккаунт); список чатов, лента и список
|
||||
получателей при пересылке читают данные напрямую через `@Query`.
|
||||
5. SwiftUI views используют один и тот же слой моделей на iOS/iPadOS/macOS.
|
||||
6. watchOS не держит отдельный XMPP-сокет: iPhone передаёт компактный snapshot,
|
||||
текстовые ответы возвращаются немедленно или через гарантированную очередь,
|
||||
@@ -60,7 +62,7 @@ Signal-криптография не блокирует главный пото
|
||||
автоматически повторяется ограниченное число раз. При уходе приложения с экрана
|
||||
и на время записи/отправки видеосообщения активный MAM-запрос закрывается, чтобы
|
||||
дешифрование истории не конкурировало с камерой и upload. Только после commit
|
||||
`AppModel` обновляет SwiftUI, локальный snapshot и Apple Watch; незавершённый
|
||||
`AppModel` обновляет SwiftUI, SwiftData-хранилище и Apple Watch; незавершённый
|
||||
проход при timeout/disconnect отбрасывается целиком.
|
||||
|
||||
Редактирование реализовано стандартным XEP-0308: исправление получает новый id и
|
||||
@@ -100,8 +102,9 @@ XEP-0424 retraction проходит через тот же plaintext/OMEMO-пу
|
||||
после чего заменяет payload tombstone, очищает медиакэш и блокирует дальнейшее
|
||||
редактирование/пересылку. Retract, пришедший раньше исходной stanza при MAM,
|
||||
временно удерживается в ограниченной очереди. Локальное удаление физически
|
||||
убирает запись из snapshot и сохраняет отдельный набор подавленных id, чтобы
|
||||
последующая MAM-синхронизация не добавила её обратно.
|
||||
удаляет строку из SwiftData-хранилища (при открытии хранилище также вычищает
|
||||
строки, помеченные удалёнными старыми сборками) и сохраняет отдельный набор
|
||||
подавленных id, чтобы последующая MAM-синхронизация не добавила её обратно.
|
||||
|
||||
Пересылка текста создаёт новое сообщение с явной подписью источника. Медиа не
|
||||
переиспользует старый `aesgcm://` URL: клиент получает расшифрованные байты и
|
||||
@@ -205,6 +208,7 @@ PushKit/CallKit и серверной APNs-инфраструктуры.
|
||||
- APNs provider + XEP-0357 registration;
|
||||
- современный `urn:xmpp:omemo:2` adapter и миграция устройств;
|
||||
- MIX и реакции;
|
||||
- SQLite/SQLCipher вместо JSON snapshot;
|
||||
- шифрование базы SQLCipher поверх SwiftData SQLite (история уже хранится
|
||||
в SwiftData, а не в JSON snapshot);
|
||||
- PushKit/CallKit для фоновых входящих звонков и групповые звонки;
|
||||
- share extension и notification service extension.
|
||||
+13
-11
@@ -1,7 +1,7 @@
|
||||
# Безопасность и модель угроз MVP
|
||||
|
||||
- Пароль XMPP сохраняется в Keychain и не попадает в `UserDefaults` или
|
||||
snapshot истории.
|
||||
локальное хранилище истории.
|
||||
- Проверка сертификата не отключается. Ручной host меняет маршрут подключения,
|
||||
но XMPP domain/JID остаётся исходной идентичностью.
|
||||
- TLS trust оценивается системным Apple Security framework как сертификат
|
||||
@@ -49,22 +49,24 @@
|
||||
STUN/TURN-сервис видит сетевые адреса и объём трафика. TURN ретранслирует уже
|
||||
зашифрованный медиапоток. Если Prosody не публикует собственный сервис через
|
||||
XEP-0215, резервный публичный STUN получает запрос на определение адреса.
|
||||
- На iOS файлы OMEMO-состояния и локальной истории получают data-protection
|
||||
`completeUntilFirstUserAuthentication`.
|
||||
- На iOS файл OMEMO-состояния и база локальной истории (SwiftData
|
||||
`.store`) получают data-protection `completeUntilFirstUserAuthentication`.
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
- На macOS история и OMEMO state лежат в sandbox Application Support без
|
||||
дополнительного SQLCipher-слоя; защиту обеспечивает учётная запись и FileVault
|
||||
пользователя. Для повышенной модели угроз нужна зашифрованная база.
|
||||
- На macOS история (SwiftData SQLite в Application Support) и OMEMO state
|
||||
лежат в sandbox без дополнительного SQLCipher-слоя; защиту обеспечивает
|
||||
учётная запись и FileVault пользователя. Для повышенной модели угроз нужна
|
||||
зашифрованная база.
|
||||
- Локальная история содержит уже расшифрованные тексты, как и у большинства
|
||||
клиентов. Полное удаление требует выхода с опцией удаления истории.
|
||||
- «Удалить у меня» удаляет запись только из локального snapshot этого устройства
|
||||
и запоминает id против повторной MAM-загрузки; оно не удаляет серверный архив,
|
||||
другие собственные устройства или копию собеседника.
|
||||
- «Удалить у меня» удаляет запись только из локального SwiftData-хранилища
|
||||
этого устройства и запоминает id против повторной MAM-загрузки; оно не
|
||||
удаляет серверный архив, другие собственные устройства или копию собеседника.
|
||||
- Глобальная политика шифрования хранится в `UserDefaults` отдельно для каждого
|
||||
JID, а переопределение чата — в локальном snapshot. Эти значения не являются
|
||||
секретами, но прямо влияют на конфиденциальность следующей отправки.
|
||||
JID, а переопределение чата — в локальном SwiftData-хранилище. Эти значения
|
||||
не являются секретами, но прямо влияют на конфиденциальность следующей
|
||||
отправки.
|
||||
- Аватары XEP-0084/vCard не шифруются OMEMO. Их видимость определяется
|
||||
настройками PEP и roster на сервере; не используйте аватар как секретное фото.
|
||||
- Используемая реализация MartinOMEMO поддерживает распространённый legacy
|
||||
|
||||
Reference in new issue
Block a user