comparison 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
comparison
equal deleted inserted replaced
3084:ffcdd93b61fa 3085:c048fc192739
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 2
4 # SAT plugin for OMEMO encryption 3 # SAT plugin for OMEMO encryption
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) 4 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
6 5
7 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
59 C.PI_MAIN: "OMEMO", 58 C.PI_MAIN: "OMEMO",
60 C.PI_HANDLER: "no", 59 C.PI_HANDLER: "no",
61 C.PI_DESCRIPTION: _("""Implementation of OMEMO"""), 60 C.PI_DESCRIPTION: _("""Implementation of OMEMO"""),
62 } 61 }
63 62
64 OMEMO_MIN_VER = (0, 10, 4) 63 OMEMO_MIN_VER = (0, 11, 0)
65 NS_OMEMO = "eu.siacs.conversations.axolotl" 64 NS_OMEMO = "eu.siacs.conversations.axolotl"
66 NS_OMEMO_DEVICES = NS_OMEMO + ".devicelist" 65 NS_OMEMO_DEVICES = NS_OMEMO + ".devicelist"
67 NS_OMEMO_BUNDLE = NS_OMEMO + ".bundles:{device_id}" 66 NS_OMEMO_BUNDLE = NS_OMEMO + ".bundles:{device_id}"
68 KEY_STATE = "STATE" 67 KEY_STATE = "STATE"
69 KEY_DEVICE_ID = "DEVICE_ID" 68 KEY_DEVICE_ID = "DEVICE_ID"
358 additional_information=additional_information, 357 additional_information=additional_information,
359 allow_untrusted=allow_untrusted 358 allow_untrusted=allow_untrusted
360 ) 359 )
361 return promise2Deferred(decrypt_mess_p) 360 return promise2Deferred(decrypt_mess_p)
362 361
363 def trust(self, bare_jid, device, key): 362 def setTrust(self, bare_jid, device, key, trusted):
364 bare_jid = bare_jid.userhost() 363 bare_jid = bare_jid.userhost()
365 trust_p = self._session.trust( 364 setTrust_p = self._session.setTrust(
366 bare_jid=bare_jid, 365 bare_jid=bare_jid,
367 device=device, 366 device=device,
368 key=key) 367 key=key,
369 return promise2Deferred(trust_p) 368 trusted=trusted,
370 369 )
371 def distrust(self, bare_jid, device, key): 370 return promise2Deferred(setTrust_p)
372 bare_jid = bare_jid.userhost()
373 distrust_p = self._session.distrust(
374 bare_jid=bare_jid,
375 device=device,
376 key=key)
377 return promise2Deferred(distrust_p)
378 371
379 def getTrustForJID(self, bare_jid): 372 def getTrustForJID(self, bare_jid):
380 bare_jid = bare_jid.userhost() 373 bare_jid = bare_jid.userhost()
381 get_trust_p = self._session.getTrustForJID(bare_jid=bare_jid) 374 get_trust_p = self._session.getTrustForJID(bare_jid=bare_jid)
382 return promise2Deferred(get_trust_p) 375 return promise2Deferred(get_trust_p)
416 trust_id = key[6:] 409 trust_id = key[6:]
417 else: 410 else:
418 continue 411 continue
419 data = trust_data[trust_id] 412 data = trust_data[trust_id]
420 trust = C.bool(value) 413 trust = C.bool(value)
421 if trust: 414 yield session.setTrust(
422 yield session.trust(data["jid"], 415 data["jid"],
423 data["device"], 416 data["device"],
424 data["ik"]) 417 data["ik"],
425 else: 418 trusted=trust,
426 yield session.distrust(data["jid"], 419 )
427 data["device"], 420 if not trust and expect_problems is not None:
428 data["ik"]) 421 expect_problems.setdefault(data['jid'].userhost(), set()).add(
429 if expect_problems is not None: 422 data['device']
430 expect_problems.setdefault(data.bare_jid, set()).add(data.device) 423 )
431 defer.returnValue({}) 424 defer.returnValue({})
432 425
433 @defer.inlineCallbacks 426 @defer.inlineCallbacks
434 def getTrustUI(self, client, entity_jid=None, trust_data=None, submit_id=None): 427 def getTrustUI(self, client, entity_jid=None, trust_data=None, submit_id=None):
435 """Generate a XMLUI to manage trust 428 """Generate a XMLUI to manage trust
805 This dict will list devices where problems can be ignored 798 This dict will list devices where problems can be ignored
806 (those devices won't receive the encrypted data) 799 (those devices won't receive the encrypted data)
807 This dict is updated 800 This dict is updated
808 """ 801 """
809 # FIXME: not all problems are handled yet 802 # FIXME: not all problems are handled yet
810 untrusted = {} 803 undecided = {}
811 missing_bundles = {} 804 missing_bundles = {}
805 found_bundles = None
812 cache = client._xep_0384_cache 806 cache = client._xep_0384_cache
813 for problem in problems: 807 for problem in problems:
814 if isinstance(problem, omemo_excpt.TrustException): 808 if isinstance(problem, omemo_excpt.TrustException):
815 untrusted[str(hash(problem))] = problem 809 if problem.problem == 'undecided':
810 undecided[str(hash(problem))] = problem
811 elif problem.problem == 'untrusted':
812 expect_problems.setdefault(problem.bare_jid, set()).add(
813 problem.device)
814 log.info(_(
815 "discarding untrusted device {device_id} with key {device_key} "
816 "for {entity}").format(
817 device_id=problem.device,
818 device_key=problem.ik.hex().upper(),
819 entity=problem.bare_jid,
820 )
821 )
822 else:
823 log.error(
824 f"Unexpected trust problem: {problem.problem!r} for device "
825 f"{problem.device} for {problem.bare_jid}, ignoring device")
826 expect_problems.setdefault(problem.bare_jid, set()).add(
827 problem.device)
816 elif isinstance(problem, omemo_excpt.MissingBundleException): 828 elif isinstance(problem, omemo_excpt.MissingBundleException):
817 pb_entity = jid.JID(problem.bare_jid) 829 pb_entity = jid.JID(problem.bare_jid)
818 entity_cache = cache.setdefault(pb_entity, {}) 830 entity_cache = cache.setdefault(pb_entity, {})
819 entity_bundles = bundles.setdefault(pb_entity, {}) 831 entity_bundles = bundles.setdefault(pb_entity, {})
820 if problem.device in entity_cache: 832 if problem.device in entity_cache:
828 missing_bundles.setdefault(pb_entity, set()).add( 840 missing_bundles.setdefault(pb_entity, set()).add(
829 problem.device) 841 problem.device)
830 expect_problems.setdefault(problem.bare_jid, set()).add( 842 expect_problems.setdefault(problem.bare_jid, set()).add(
831 problem.device) 843 problem.device)
832 elif isinstance(problem, omemo_excpt.NoEligibleDevicesException): 844 elif isinstance(problem, omemo_excpt.NoEligibleDevicesException):
833 if untrusted or found_bundles: 845 if undecided or found_bundles:
834 # we may have new devices after this run, so let's continue for now 846 # we may have new devices after this run, so let's continue for now
835 continue 847 continue
836 else: 848 else:
837 raise problem 849 raise problem
838 else: 850 else:
849 D_("You're destinee {peer} has missing encryption data on some of " 861 D_("You're destinee {peer} has missing encryption data on some of "
850 "his/her device(s) (bundle on device {devices}), the message won't " 862 "his/her device(s) (bundle on device {devices}), the message won't "
851 "be readable on this/those device.").format( 863 "be readable on this/those device.").format(
852 peer=peer_jid.full(), devices=", ".join(devices_s))) 864 peer=peer_jid.full(), devices=", ".join(devices_s)))
853 865
854 if untrusted: 866 if undecided:
855 trust_data = {} 867 trust_data = {}
856 for trust_id, data in untrusted.items(): 868 for trust_id, data in undecided.items():
857 trust_data[trust_id] = { 869 trust_data[trust_id] = {
858 'jid': jid.JID(data.bare_jid), 870 'jid': jid.JID(data.bare_jid),
859 'device': data.device, 871 'device': data.device,
860 'ik': data.ik} 872 'ik': data.ik}
861 873