diff sat/plugins/plugin_xep_0384.py @ 3085:c048fc192739

plugin XEP-0384: update to latest python-omemo + better trust management: - python-omemo minimal version is now 0.11.0 - `undecided` devices are now handled, fixing the "accept all or none" issue: if a device is `undecided`, the trust manager will be shown with the missing devices before sending the message. - `untrusted` devices are discarded
author Goffi <goffi@goffi.org>
date Fri, 20 Dec 2019 12:28:01 +0100
parents ffcdd93b61fa
children 518208085dfb
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0384.py	Sat Dec 07 11:30:56 2019 +0100
+++ b/sat/plugins/plugin_xep_0384.py	Fri Dec 20 12:28:01 2019 +0100
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# -*- coding: utf-8 -*-
 
 # SAT plugin for OMEMO encryption
 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
@@ -61,7 +60,7 @@
     C.PI_DESCRIPTION: _("""Implementation of OMEMO"""),
 }
 
-OMEMO_MIN_VER = (0, 10, 4)
+OMEMO_MIN_VER = (0, 11, 0)
 NS_OMEMO = "eu.siacs.conversations.axolotl"
 NS_OMEMO_DEVICES = NS_OMEMO + ".devicelist"
 NS_OMEMO_BUNDLE = NS_OMEMO + ".bundles:{device_id}"
@@ -360,21 +359,15 @@
             )
         return promise2Deferred(decrypt_mess_p)
 
-    def trust(self, bare_jid, device, key):
+    def setTrust(self, bare_jid, device, key, trusted):
         bare_jid = bare_jid.userhost()
-        trust_p = self._session.trust(
+        setTrust_p = self._session.setTrust(
             bare_jid=bare_jid,
             device=device,
-            key=key)
-        return promise2Deferred(trust_p)
-
-    def distrust(self, bare_jid, device, key):
-        bare_jid = bare_jid.userhost()
-        distrust_p = self._session.distrust(
-            bare_jid=bare_jid,
-            device=device,
-            key=key)
-        return promise2Deferred(distrust_p)
+            key=key,
+            trusted=trusted,
+        )
+        return promise2Deferred(setTrust_p)
 
     def getTrustForJID(self, bare_jid):
         bare_jid = bare_jid.userhost()
@@ -418,16 +411,16 @@
                 continue
             data = trust_data[trust_id]
             trust = C.bool(value)
-            if trust:
-                yield session.trust(data["jid"],
-                                    data["device"],
-                                    data["ik"])
-            else:
-                yield session.distrust(data["jid"],
-                                       data["device"],
-                                       data["ik"])
-                if expect_problems is not None:
-                    expect_problems.setdefault(data.bare_jid, set()).add(data.device)
+            yield session.setTrust(
+                data["jid"],
+                data["device"],
+                data["ik"],
+                trusted=trust,
+            )
+            if not trust and expect_problems is not None:
+                expect_problems.setdefault(data['jid'].userhost(), set()).add(
+                    data['device']
+                )
         defer.returnValue({})
 
     @defer.inlineCallbacks
@@ -807,12 +800,31 @@
             This dict is updated
         """
         # FIXME: not all problems are handled yet
-        untrusted = {}
+        undecided = {}
         missing_bundles = {}
+        found_bundles = None
         cache = client._xep_0384_cache
         for problem in problems:
             if isinstance(problem, omemo_excpt.TrustException):
-                untrusted[str(hash(problem))] = problem
+                if problem.problem == 'undecided':
+                    undecided[str(hash(problem))] = problem
+                elif problem.problem == 'untrusted':
+                    expect_problems.setdefault(problem.bare_jid, set()).add(
+                        problem.device)
+                    log.info(_(
+                        "discarding untrusted device {device_id} with key {device_key} "
+                        "for {entity}").format(
+                            device_id=problem.device,
+                            device_key=problem.ik.hex().upper(),
+                            entity=problem.bare_jid,
+                        )
+                    )
+                else:
+                    log.error(
+                        f"Unexpected trust problem: {problem.problem!r} for device "
+                        f"{problem.device} for {problem.bare_jid}, ignoring device")
+                    expect_problems.setdefault(problem.bare_jid, set()).add(
+                        problem.device)
             elif isinstance(problem, omemo_excpt.MissingBundleException):
                 pb_entity = jid.JID(problem.bare_jid)
                 entity_cache = cache.setdefault(pb_entity, {})
@@ -830,7 +842,7 @@
                         expect_problems.setdefault(problem.bare_jid, set()).add(
                             problem.device)
             elif isinstance(problem, omemo_excpt.NoEligibleDevicesException):
-                if untrusted or found_bundles:
+                if undecided or found_bundles:
                     # we may have new devices after this run, so let's continue for now
                     continue
                 else:
@@ -851,9 +863,9 @@
                    "be readable on this/those device.").format(
                    peer=peer_jid.full(), devices=", ".join(devices_s)))
 
-        if untrusted:
+        if undecided:
             trust_data = {}
-            for trust_id, data in untrusted.items():
+            for trust_id, data in undecided.items():
                 trust_data[trust_id] = {
                     'jid': jid.JID(data.bare_jid),
                     'device':  data.device,