comparison 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
comparison
equal deleted inserted replaced
2857:88f10630d5ea 2858:31a5038cdf79
781 yield self.setDevices(client, devices) 781 yield self.setDevices(client, devices)
782 782
783 ## triggers 783 ## triggers
784 784
785 @defer.inlineCallbacks 785 @defer.inlineCallbacks
786 def handleProblems(self, client, entity, bundles, problems): 786 def handleProblems(self, client, entity, bundles, expect_problems, problems):
787 """Try to solve problem found by EncryptMessage 787 """Try to solve problems found by EncryptMessage
788 788
789 @param entity(jid.JID): bare jid of the destinee 789 @param entity(jid.JID): bare jid of the destinee
790 @param bundles(dict): bundles data as used in EncryptMessage 790 @param bundles(dict): bundles data as used in EncryptMessage
791 already filled with known bundles, missing bundles 791 already filled with known bundles, missing bundles
792 need to be added to it 792 need to be added to it
793 This dict is updated
793 @param problems(list): exceptions raised by EncryptMessage 794 @param problems(list): exceptions raised by EncryptMessage
794 @return (dict): expect_problems arguments, used in EncryptMessage 795 @param expect_problems(dict): known problems to expect, used in encryptMessage
795 this dict will list devices where problems can be ignored 796 This dict will list devices where problems can be ignored
796 (those devices won't receive the encrypted data) 797 (those devices won't receive the encrypted data)
798 This dict is updated
797 """ 799 """
798 # FIXME: not all problems are handled yet 800 # FIXME: not all problems are handled yet
799 untrusted = {} 801 untrusted = {}
800 missing_bundles = {} 802 missing_bundles = {}
801 expect_problems = {}
802 cache = client._xep_0384_cache 803 cache = client._xep_0384_cache
803 for problem in problems: 804 for problem in problems:
804 if isinstance(problem, omemo_excpt.TrustException): 805 if isinstance(problem, omemo_excpt.TrustException):
805 untrusted[unicode(hash(problem))] = problem 806 untrusted[unicode(hash(problem))] = problem
806 if isinstance(problem, omemo_excpt.MissingBundleException): 807 elif isinstance(problem, omemo_excpt.MissingBundleException):
807 pb_entity = jid.JID(problem.bare_jid) 808 pb_entity = jid.JID(problem.bare_jid)
808 entity_cache = cache.setdefault(pb_entity, {}) 809 entity_cache = cache.setdefault(pb_entity, {})
809 entity_bundles = bundles.setdefault(pb_entity, {}) 810 entity_bundles = bundles.setdefault(pb_entity, {})
810 if problem.device in entity_cache: 811 if problem.device in entity_cache:
811 entity_bundles[problem.device] = entity_cache[problem.device] 812 entity_bundles[problem.device] = entity_cache[problem.device]
817 if problem.device in missing: 818 if problem.device in missing:
818 missing_bundles.setdefault(pb_entity, set()).add( 819 missing_bundles.setdefault(pb_entity, set()).add(
819 problem.device) 820 problem.device)
820 expect_problems.setdefault(problem.bare_jid, set()).add( 821 expect_problems.setdefault(problem.bare_jid, set()).add(
821 problem.device) 822 problem.device)
822 elif isinstance(problem, omemo_excpt.NoEligibleDevicesException): 823 else:
823 pass 824 raise problem
824 825
825 for peer_jid, devices in missing_bundles.iteritems(): 826 for peer_jid, devices in missing_bundles.iteritems():
826 devices_s = [unicode(d) for d in devices] 827 devices_s = [unicode(d) for d in devices]
827 log.warning( 828 log.warning(
828 _(u"Can't retrieve bundle for device(s) {devices} of entity {peer}, " 829 _(u"Can't retrieve bundle for device(s) {devices} of entity {peer}, "
857 u"meta_encryption_trust": NS_OMEMO, 858 u"meta_encryption_trust": NS_OMEMO,
858 }, 859 },
859 profile=client.profile) 860 profile=client.profile)
860 yield self.trustUICb(answer, trust_data, expect_problems, client.profile) 861 yield self.trustUICb(answer, trust_data, expect_problems, client.profile)
861 862
862 defer.returnValue(expect_problems)
863
864 @defer.inlineCallbacks 863 @defer.inlineCallbacks
865 def encryptMessage(self, client, entity_bare_jid, message): 864 def encryptMessage(self, client, entity_bare_jid, message):
866 omemo_session = client._xep_0384_session 865 omemo_session = client._xep_0384_session
866 expect_problems = {}
867 bundles = {}
868 loop_idx = 0
867 try: 869 try:
868 # first try may fail, in case of e.g. trust issue or missing bundle 870 while True:
869 encrypted = yield omemo_session.encryptMessage( 871 if loop_idx > 10:
870 entity_bare_jid, 872 msg = _(u"Too many iterations in encryption loop")
871 message) 873 log.error(msg)
872 except omemo_excpt.EncryptionProblemsException as e: 874 raise exceptions.InternalError(msg)
873 # we know the problem to solve, we can try to fix them 875 # encryptMessage may fail, in case of e.g. trust issue or missing bundle
874 bundles = {} 876 try:
875 expect_problems = yield self.handleProblems(client, entity_bare_jid, bundles, 877 encrypted = yield omemo_session.encryptMessage(
876 e.problems) 878 entity_bare_jid,
877 # and try an encryption again. 879 message,
878 try: 880 bundles,
879 encrypted = yield omemo_session.encryptMessage( 881 expect_problems = expect_problems)
880 entity_bare_jid, 882 except omemo_excpt.EncryptionProblemsException as e:
881 message, 883 # we know the problem to solve, we can try to fix them
882 bundles, 884 yield self.handleProblems(
883 expect_problems = expect_problems) 885 client,
884 except omemo_excpt.EncryptionProblemsException as e: 886 entity=entity_bare_jid,
885 log.warning( 887 bundles=bundles,
886 _(u"Can't encrypt message for {entity}: {reason}".format( 888 expect_problems=expect_problems,
887 entity=entity_bare_jid.full(), reason=e))) 889 problems=e.problems)
888 raise e 890 loop_idx += 1
891 else:
892 break
893 except Exception as e:
894 log.warning(
895 _(u"Can't encrypt message for {entity}: {reason}".format(
896 entity=entity_bare_jid.full(), reason=str(e).decode('utf-8', 'replace'))))
897 raise e
889 898
890 defer.returnValue(encrypted) 899 defer.returnValue(encrypted)
891 900
892 @defer.inlineCallbacks 901 @defer.inlineCallbacks
893 def _messageReceivedTrigger(self, client, message_elt, post_treat): 902 def _messageReceivedTrigger(self, client, message_elt, post_treat):