diff --git a/Sources/Shared/Models/AppModel.swift b/Sources/Shared/Models/AppModel.swift index b411e25..e98c63b 100644 --- a/Sources/Shared/Models/AppModel.swift +++ b/Sources/Shared/Models/AppModel.swift @@ -1460,6 +1460,14 @@ final class AppModel: ObservableObject { } func encryptionEnabled(for jid: String) -> Bool { + // A conversation with the account's own bare JID is a self-chat. + // OMEMO to oneself is meaningless and would force MartinOMEMO to build + // a cryptographically invalid self-session (see + // `LumaOMEMOStore.removeSessionWithOwnDevice`), producing messages + // that later fail to decrypt. Always send self-chat plaintext. + if let account, jid.lowercased() == account.normalizedJID { + return false + } return encryptionPreference(for: jid).resolved(globalEnabled: globalEncryptionEnabled) } diff --git a/Sources/Shared/XMPP/XMPPService.swift b/Sources/Shared/XMPP/XMPPService.swift index c001492..73ab80d 100644 --- a/Sources/Shared/XMPP/XMPPService.swift +++ b/Sources/Shared/XMPP/XMPPService.swift @@ -1770,12 +1770,15 @@ final class XMPPService { fingerprint = nil contentMessage = message default: - // Includes `.duplicateMessage` (our own message without an - // encrypt-to-self key, or a key already consumed by a previous - // session): the body can no longer be recovered here. Still - // emit the message (as an undecryptable bubble) instead of - // dropping it, so history does not silently stop. Genuine - // duplicates are filtered later in AppModel by stanza/origin ID. + // `.duplicateMessage` (our own message whose encrypt-to-self + // key was already consumed) or any other OMEMO failure on a + // message we authored cannot recover the body here. We already + // hold the plaintext for outgoing messages (optimistic insert + // or the live echo), so drop the echo instead of surfacing a + // spurious "undecryptable" bubble. This mirrors the group + // handler and keeps self-chat from filling with failure + // placeholders. + if outgoing { return } security = .decryptionFailed fingerprint = nil contentMessage = nil