changeset 3240:d85b68e44297

plugin XEP-0384: fixed /omemo_reset + device ID type: - the workflow done with /omemo_reset is now using the right methods (encryptRatchetForwardingMessage and decryptRatchetForwardingMessage) - fixed type error with device when calling python-omemo methods: a mix of str and int was leading to two caches being created, and random bugs
author Goffi <goffi@goffi.org>
date Mon, 30 Mar 2020 19:59:17 +0200
parents 4396bf14f5fc
children 46f0b388eeea
files sat/plugins/plugin_xep_0384.py
diffstat 1 files changed, 66 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0384.py	Mon Mar 30 19:59:14 2020 +0200
+++ b/sat/plugins/plugin_xep_0384.py	Mon Mar 30 19:59:17 2020 +0200
@@ -142,7 +142,7 @@
         deferred.addErrback(partial(callback, False))
 
     def _checkJid(self, bare_jid):
-        """Check if jid is know, and store it if not
+        """Check if jid is known, and store it if not
 
         @param bare_jid(unicode): bare jid to check
         @return (D): Deferred fired when jid is stored
@@ -329,12 +329,13 @@
 
     def buildSession(self, bare_jid, device, bundle):
         bare_jid = bare_jid.userhost()
-        build_session_p = self._session.buildSession(bare_jid, device, bundle)
+        build_session_p = self._session.buildSession(bare_jid, int(device), bundle)
         return promise2Deferred(build_session_p)
 
     def deleteSession(self, bare_jid, device):
         bare_jid = bare_jid.userhost()
-        delete_session_p = self._session.deleteSession(bare_jid=bare_jid, device=device)
+        delete_session_p = self._session.deleteSession(
+            bare_jid=bare_jid, device=int(device))
         return promise2Deferred(delete_session_p)
 
     def encryptMessage(self, bare_jids, message, bundles=None, expect_problems=None):
@@ -356,12 +357,23 @@
             expect_problems=expect_problems)
         return promise2Deferred(encrypt_mess_p)
 
+    def encryptRatchetForwardingMessage(
+        self, bare_jids, bundles=None, expect_problems=None):
+        bare_jids = [e.userhost() for e in bare_jids]
+        if bundles is not None:
+            bundles = {e.userhost(): v for e, v in bundles.items()}
+        encrypt_ratchet_fwd_p = self._session.encryptRatchetForwardingMessage(
+            bare_jids=bare_jids,
+            bundles=bundles,
+            expect_problems=expect_problems)
+        return promise2Deferred(encrypt_ratchet_fwd_p)
+
     def decryptMessage(self, bare_jid, device, iv, message, is_pre_key_message,
                        ciphertext, additional_information=None, allow_untrusted=False):
         bare_jid = bare_jid.userhost()
         decrypt_mess_p = self._session.decryptMessage(
             bare_jid=bare_jid,
-            device=device,
+            device=int(device),
             iv=iv,
             message=message,
             is_pre_key_message=is_pre_key_message,
@@ -371,11 +383,26 @@
             )
         return promise2Deferred(decrypt_mess_p)
 
+    def decryptRatchetForwardingMessage(
+        self, bare_jid, device, iv, message, is_pre_key_message,
+        additional_information=None, allow_untrusted=False):
+        bare_jid = bare_jid.userhost()
+        decrypt_ratchet_fwd_p = self._session.decryptRatchetForwardingMessage(
+            bare_jid=bare_jid,
+            device=int(device),
+            iv=iv,
+            message=message,
+            is_pre_key_message=is_pre_key_message,
+            additional_information=additional_information,
+            allow_untrusted=allow_untrusted
+            )
+        return promise2Deferred(decrypt_ratchet_fwd_p)
+
     def setTrust(self, bare_jid, device, key, trusted):
         bare_jid = bare_jid.userhost()
         setTrust_p = self._session.setTrust(
             bare_jid=bare_jid,
-            device=device,
+            device=int(device),
             key=key,
             trusted=trusted,
         )
@@ -385,7 +412,7 @@
         bare_jid = bare_jid.userhost()
         resetTrust_p = self._session.resetTrust(
             bare_jid=bare_jid,
-            device=device,
+            device=int(device),
         )
         return promise2Deferred(resetTrust_p)
 
@@ -674,8 +701,7 @@
 
         return xmlui
 
-    @defer.inlineCallbacks
-    def profileConnected(self, client):
+    async def profileConnected(self, client):
         if self._m is not None:
             # we keep plain text message for MUC messages we send
             # as we can't encrypt for our own device
@@ -691,9 +717,9 @@
         persistent_dict = persistent.LazyPersistentBinaryDict("XEP-0384", client.profile)
         client._xep_0384_data = persistent_dict
         # all known devices of profile
-        devices = yield self.getDevices(client)
+        devices = await self.getDevices(client)
         # and our own device id
-        device_id = yield persistent_dict.get(KEY_DEVICE_ID)
+        device_id = await persistent_dict.get(KEY_DEVICE_ID)
         if device_id is None:
             log.info(_("We have no identity for this device yet, let's generate one"))
             # we have a new device, we create device_id
@@ -709,25 +735,26 @@
         if device_id not in devices:
             log.debug(f"our device id ({device_id}) is not in the list, adding it")
             devices.add(device_id)
-            yield defer.ensureDeferred(self.setDevices(client, devices))
+            await defer.ensureDeferred(self.setDevices(client, devices))
 
-        all_jids = yield persistent_dict.get(KEY_ALL_JIDS, set())
+        all_jids = await persistent_dict.get(KEY_ALL_JIDS, set())
 
         omemo_storage = OmemoStorage(client, device_id, all_jids)
-        omemo_session = yield OmemoSession.create(client, omemo_storage, device_id)
+        omemo_session = await OmemoSession.create(client, omemo_storage, device_id)
         client._xep_0384_cache = {}
         client._xep_0384_session = omemo_session
         client._xep_0384_device_id = device_id
-        yield omemo_session.newDeviceList(client.jid, devices)
+        await omemo_session.newDeviceList(client.jid, devices)
         if omemo_session.republish_bundle:
             log.info(_("Saving public bundle for this device ({device_id})").format(
                 device_id=device_id))
-            yield defer.ensureDeferred(
+            await defer.ensureDeferred(
                 self.setBundle(client, omemo_session.public_bundle, device_id)
             )
         client._xep_0384_ready.callback(None)
         del client._xep_0384_ready
 
+
     ## XMPP PEP nodes manipulation
 
     # devices
@@ -1126,11 +1153,17 @@
                     raise exceptions.InternalError(msg)
                 # encryptMessage may fail, in case of e.g. trust issue or missing bundle
                 try:
-                    encrypted = await omemo_session.encryptMessage(
-                        entity_bare_jids,
-                        message,
-                        bundles,
-                        expect_problems = expect_problems)
+                    if not message:
+                        encrypted = await omemo_session.encryptRatchetForwardingMessage(
+                            entity_bare_jids,
+                            bundles,
+                            expect_problems = expect_problems)
+                    else:
+                        encrypted = await omemo_session.encryptMessage(
+                            entity_bare_jids,
+                            message,
+                            bundles,
+                            expect_problems = expect_problems)
                 except omemo_excpt.EncryptionProblemsException as e:
                     # we know the problem to solve, we can try to fix them
                     await self.handleProblems(
@@ -1275,21 +1308,24 @@
                 "iv": base64.b64decode(bytes(iv_elt)),
                 "message": base64.b64decode(bytes(key_elt)),
                 "is_pre_key_message": is_pre_key,
-                "ciphertext": base64.b64decode(bytes(payload_elt))
-                    if payload_elt is not None else None,
                 "additional_information":  additional_information,
             }
 
             try:
-                try:
-                    plaintext = yield omemo_session.decryptMessage(**kwargs)
-                except omemo_excpt.TrustException:
-                    post_treat.addCallback(client.encryption.markAsUntrusted)
-                    kwargs['allow_untrusted'] = True
-                    plaintext = yield omemo_session.decryptMessage(**kwargs)
+                if payload_elt is None:
+                    omemo_session.decryptRatchetForwardingMessage(**kwargs)
+                    plaintext = None
                 else:
-                    post_treat.addCallback(client.encryption.markAsTrusted)
-                plaintext = plaintext.decode()
+                    kwargs["ciphertext"] = base64.b64decode(bytes(payload_elt))
+                    try:
+                        plaintext = yield omemo_session.decryptMessage(**kwargs)
+                    except omemo_excpt.TrustException:
+                        post_treat.addCallback(client.encryption.markAsUntrusted)
+                        kwargs['allow_untrusted'] = True
+                        plaintext = yield omemo_session.decryptMessage(**kwargs)
+                    else:
+                        post_treat.addCallback(client.encryption.markAsTrusted)
+                    plaintext = plaintext.decode()
             except Exception as e:
                 log.warning(_("Can't decrypt message: {reason}\n{xml}").format(
                     reason=e, xml=message_elt.toXml()))