| author | Matthew Wild
<mwild1@gmail.com> 2025-04-22 19:22:03 UTC |
| committer | Matthew Wild
<mwild1@gmail.com> 2025-04-22 19:22:03 UTC |
| parent | ea9795bac6adf0a820a4767ef18daa660165b004 |
| doc/OMEMO.md | +0 | -1 |
| snikket/Client.hx | +7 | -0 |
| snikket/OMEMO.hx | +32 | -3 |
diff --git a/doc/OMEMO.md b/doc/OMEMO.md index e25d16f..edaa116 100644 --- a/doc/OMEMO.md +++ b/doc/OMEMO.md @@ -15,6 +15,5 @@ compile with the NO_OMEMO flag. - Persistence: only IndexedDB backend is currently implemented - Encryption status reported by the API can be forged by sender - Consumed prekeys are not removed and replaced -- Messages to recipients with no published keys fail to send - Outgoing messages are not encrypted to the sending account's other devices - No support for group chats diff --git a/snikket/Client.hx b/snikket/Client.hx index 3ca56b3..8b7e998 100644 --- a/snikket/Client.hx +++ b/snikket/Client.hx @@ -11,6 +11,7 @@ import snikket.ChatMessage; import snikket.Message; import snikket.EventEmitter; import snikket.EventHandler; +import snikket.EncryptionPolicy; #if !NO_OMEMO import snikket.OMEMO; #end @@ -94,6 +95,12 @@ class Client extends EventEmitter { private var fastMechanism: Null<String> = null; private var token: Null<String> = null; private final pendingCaps: Map<String, Array<(Null<Caps>)->Chat>> = []; + @:allow(snikket) + private final encryptionPolicy:EncryptionPolicy = { + allowUnencryptedOutgoing: true, + allowUnencryptedIncoming: true, + preferEncryptedOutgoing: true, + }; #if !NO_OMEMO @:allow(snikket) diff --git a/snikket/OMEMO.hx b/snikket/OMEMO.hx index bb00538..bc6568a 100644 --- a/snikket/OMEMO.hx +++ b/snikket/OMEMO.hx @@ -923,9 +923,9 @@ class OMEMO { promRecipientDevices.then((recipientDevices) -> { promEncryptedMessage.then((encryptionResult) -> { buildOMEMOHeader(encryptionResult, deviceId, recipient.asString(), recipientDevices).then(resolve, reject); - }); - }); - }); + }, reject); + }, reject); + }, reject); }); final promStanza = promHeader.then((header) -> { @@ -935,6 +935,35 @@ class OMEMO { newStanza.textTag("encryption", "", { xmlns: "urn:xmpp:eme:0", namespace: "eu.siacs.conversations.axolotl" }); newStanza.textTag("body", "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"); return newStanza; + }, (failureReason) -> { + final noRecipientSupport = failureReason == "no-devices"; + var allowUnencrypted:Bool = client.encryptionPolicy.allowUnencryptedOutgoing; + + var errMsg:String; + if(noRecipientSupport) { + errMsg = "Encryption failed because no recipient devices could be found"; + } else { + errMsg = "Encryption failed due to internal error: " + failureReason; + // Since this failure is not expected, we'll only allow the stanza + // through if the policy does not prefer encrypted communications. If + // encrypted communication *is* preferred, we need a good excuse to + // send unencrypted (such as no recipient support), but no such excuse + // is found here. + allowUnencrypted = allowUnencrypted && !client.encryptionPolicy.preferEncryptedOutgoing; + } + + if(!allowUnencrypted) { + // Policy forbids outgoing unencrypted messages or some unexpected + // error occurred (the latter is not a reason to override preferences) + // FIXME: We need to report this to the UI somehow + throw "Unable to send message: " + errMsg; + } + + trace("OMEMO: Skipping encryption (permitted by policy): " + errMsg); + + // Encryption failed, but policy says this is ok. + // Just pass through the original stanza to be sent. + return stanza; }); return promStanza;