- Purge the poisoned self-session only once per account instead of on
every connect, and rebuild it from the own published bundle when
missing: deleting it repeatedly broke encrypt-to-self, so archived
copies of own messages (most visibly in the self-chat) failed with
"could not decrypt".
- Detect OMEMO 2 (urn:xmpp:omemo:2) payloads, which the pinned
MartinOMEMO does not implement, and show them as undecryptable
instead of empty plaintext bubbles.
- Guard both behaviours in verify.sh and document the namespace
limitation in SECURITY.md.
- After a call ends, send a plaintext <call-history/> service message
to the user's own bare JID with direction, status, duration, start
time, peer and video flag plus the call id as origin-id.
- Intercept the payload on live, carbon and MAM paths and upsert the
same system call card on every device; deduplication reuses the
origin-id as clientID, and missed incoming calls bump unread.
- Cover payload parsing and round-trip in CallHistorySyncTests, guard
the namespace and interception in verify.sh, and document the flow
in ARCHITECTURE.md.
- Gate every layer behind AppLockView when the lock is enabled and
lock on launch and on backgrounding; the passcode lives only in the
Keychain (AppLockVault) and the enable state defaults to off.
- Add the lock section to Settings: enable/setup, change passcode and
disable all require the current passcode via a shared passcode
sheet; Face ID / Touch ID unlock prompts automatically and can be
toggled with passcode confirmation.
- Add NSFaceIDUsageDescription to both app targets, cover the passcode
policy with tests, guard the feature in verify.sh and document it in
SECURITY.md.
- Implement SCRAM-SHA-512 (RFC 5802 with SHA-512) as a Luma-side
SaslMechanism and register it ahead of Martin's SHA-256/SHA-1/PLAIN,
so modern servers preferring SHA-512 authenticate with it.
- Verify the math against Python-computed reference vectors (salted
password, client proof, server signature) in SCRAMSHA512Tests and
guard the mechanism registration in Scripts/verify.sh.
- Confirm the TLS stack negotiates TLS 1.3 (negotiatedSSL + ALPN via
SecureTransport, handshake verified against a TLS 1.3-only server)
and document the TLS/SCRAM posture in SECURITY.md.
- Delete a group chat from GroupInfoView or via a swipe in the chat
list: remove the conversation and its messages from SwiftData,
clean per-chat state, and leave the room on the server first when
joined.
- Keep "Покинуть комнату" as leave-without-deleting and suppress
deleted rooms for the session so roomState events cannot recreate
them; an explicit rejoin or a fresh invitation clears the
suppression.
- Add verify.sh invariants and document the behaviour in
ARCHITECTURE.md.
- Normalize SCRAM passwords with RFC 4013 SASLprep before the
challenge response, so they match SASLprep-compliant servers
(Martin hashes raw UTF-8) and PLAIN still sends the password
untouched.
- Capture the raw <failure/> condition with LumaSaslFailureModule and
map SASL errors to actionable Russian messages instead of the
cryptic OS-localized "Martin.SaslError, error 5".
- Cover SASLprep and failure message mapping with unit tests and new
verify.sh invariants.
- 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.
thread
- Replace O(n^2) origin-id/stanza-id lookups in AppModel with hash
indexes
and stop rebuilding the whole index on every unseen stanza-id, so
archive
application no longer grows quadratically with history size.
- Run OMEMO decryption on a serial background queue instead of the main
actor, and decrypt archived stanzas in small batches with a shorter
yield,
keeping the UI responsive during large archive catch-ups.
- Show the "Синхронизация истории…" banner only for the one-page
bootstrap
window; incremental backlog catch-up continues silently in the
background.
- Fix MUC-MAM: publish decoded group mutations at the end of room
catch-up;
they were previously accumulated and then silently dropped.
- Retry a failed catch-up pass automatically (bounded) and lengthen the
query/apply timeouts so a single slow page no longer leaves history
unloaded until the next app activation.