diff sat/plugins/plugin_xep_0384.py @ 2858:31a5038cdf79

plugin XEP-0384: small refactoring to encrypt messages + bugfix: encryptMessage is now called in a loop, because problems may happen by steps (e.g. trust issue after getting missing bundles). Fixed a mix between "if" and "elif" in problems handling,
author Goffi <goffi@goffi.org>
date Wed, 20 Mar 2019 09:08:47 +0100
parents 88f10630d5ea
children 4e875d9eea48
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0384.py	Wed Mar 20 09:08:37 2019 +0100
+++ b/sat/plugins/plugin_xep_0384.py	Wed Mar 20 09:08:47 2019 +0100
@@ -783,27 +783,28 @@
     ## triggers
 
     @defer.inlineCallbacks
-    def handleProblems(self, client, entity, bundles, problems):
-        """Try to solve problem found by EncryptMessage
+    def handleProblems(self, client, entity, bundles, expect_problems, problems):
+        """Try to solve problems found by EncryptMessage
 
         @param entity(jid.JID): bare jid of the destinee
         @param bundles(dict): bundles data as used in EncryptMessage
             already filled with known bundles, missing bundles
             need to be added to it
+            This dict is updated
         @param problems(list): exceptions raised by EncryptMessage
-        @return (dict): expect_problems arguments, used in EncryptMessage
-            this dict will list devices where problems can be ignored
+        @param expect_problems(dict): known problems to expect, used in encryptMessage
+            This dict will list devices where problems can be ignored
             (those devices won't receive the encrypted data)
+            This dict is updated
         """
         # FIXME: not all problems are handled yet
         untrusted = {}
         missing_bundles = {}
-        expect_problems = {}
         cache = client._xep_0384_cache
         for problem in problems:
             if isinstance(problem, omemo_excpt.TrustException):
                 untrusted[unicode(hash(problem))] = problem
-            if isinstance(problem, omemo_excpt.MissingBundleException):
+            elif isinstance(problem, omemo_excpt.MissingBundleException):
                 pb_entity = jid.JID(problem.bare_jid)
                 entity_cache = cache.setdefault(pb_entity, {})
                 entity_bundles = bundles.setdefault(pb_entity, {})
@@ -819,8 +820,8 @@
                             problem.device)
                         expect_problems.setdefault(problem.bare_jid, set()).add(
                             problem.device)
-            elif isinstance(problem, omemo_excpt.NoEligibleDevicesException):
-                pass
+            else:
+                raise problem
 
         for peer_jid, devices in missing_bundles.iteritems():
             devices_s = [unicode(d) for d in devices]
@@ -859,33 +860,41 @@
                 profile=client.profile)
             yield self.trustUICb(answer, trust_data, expect_problems, client.profile)
 
-        defer.returnValue(expect_problems)
-
     @defer.inlineCallbacks
     def encryptMessage(self, client, entity_bare_jid, message):
         omemo_session = client._xep_0384_session
+        expect_problems = {}
+        bundles = {}
+        loop_idx = 0
         try:
-            # first try may fail, in case of e.g. trust issue or missing bundle
-            encrypted = yield omemo_session.encryptMessage(
-                entity_bare_jid,
-                message)
-        except omemo_excpt.EncryptionProblemsException as e:
-            # we know the problem to solve, we can try to fix them
-            bundles = {}
-            expect_problems = yield self.handleProblems(client, entity_bare_jid, bundles,
-                                                        e.problems)
-            # and try an encryption again.
-            try:
-                encrypted = yield omemo_session.encryptMessage(
-                    entity_bare_jid,
-                    message,
-                    bundles,
-                    expect_problems = expect_problems)
-            except omemo_excpt.EncryptionProblemsException as e:
-                log.warning(
-                    _(u"Can't encrypt message for {entity}: {reason}".format(
-                    entity=entity_bare_jid.full(), reason=e)))
-                raise e
+            while True:
+                if loop_idx > 10:
+                    msg = _(u"Too many iterations in encryption loop")
+                    log.error(msg)
+                    raise exceptions.InternalError(msg)
+                # encryptMessage may fail, in case of e.g. trust issue or missing bundle
+                try:
+                    encrypted = yield omemo_session.encryptMessage(
+                        entity_bare_jid,
+                        message,
+                        bundles,
+                        expect_problems = expect_problems)
+                except omemo_excpt.EncryptionProblemsException as e:
+                    # we know the problem to solve, we can try to fix them
+                    yield self.handleProblems(
+                        client,
+                        entity=entity_bare_jid,
+                        bundles=bundles,
+                        expect_problems=expect_problems,
+                        problems=e.problems)
+                    loop_idx += 1
+                else:
+                    break
+        except Exception as e:
+            log.warning(
+                _(u"Can't encrypt message for {entity}: {reason}".format(
+                entity=entity_bare_jid.full(), reason=str(e).decode('utf-8', 'replace'))))
+            raise e
 
         defer.returnValue(encrypted)