changeset 2653:7213caa5c5d0

plugin OTR: integrated in new encryption handler + fixed use of bare jid where full jid was expected
author Goffi <goffi@goffi.org>
date Sat, 11 Aug 2018 18:24:55 +0200
parents baccc27d5c5c
children e7bfbded652a
files sat/plugins/plugin_sec_otr.py
diffstat 1 files changed, 32 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_sec_otr.py	Sat Aug 11 18:24:55 2018 +0200
+++ b/sat/plugins/plugin_sec_otr.py	Sat Aug 11 18:24:55 2018 +0200
@@ -123,6 +123,7 @@
         log.debug(u"setState: %s (old_state=%s)" % (state, old_state))
 
         if state == potr.context.STATE_PLAINTEXT:
+            client.encryption.stop(self.peer, NS_OTR)
             feedback = _(u"/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % {
                 "other_jid": self.peer.full()
             }
@@ -130,6 +131,7 @@
                 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile
             )
         elif state == potr.context.STATE_ENCRYPTED:
+            client.encryption.start(self.peer, NS_OTR)
             try:
                 trusted = self.getCurrentTrust()
             except TypeError:
@@ -153,6 +155,7 @@
                 OTR_STATE_ENCRYPTED, self.peer.full(), client.profile
             )
         elif state == potr.context.STATE_FINISHED:
+            client.encryption.stop(self.peer, NS_OTR)
             feedback = D_(u"OTR conversation with {other_jid} is FINISHED").format(
                 other_jid=self.peer.full()
             )
@@ -303,6 +306,7 @@
             type_=C.MENU_SINGLE,
         )
         host.trigger.add("presenceReceived", self._presenceReceivedTrigger)
+        self.host.registerEncryptionPlugin(self, u"OTR", NS_OTR)
 
     def _skipOTR(self, profile):
         """Tell the backend to not handle OTR for this profile.
@@ -361,6 +365,11 @@
 
         @param to_jid(jid.JID): jid to start encrypted session with
         """
+        encrypted_session = client.encryption.getSession(to_jid.userhostJID())
+        if encrypted_session and encrypted_session[u'plugin'].namespace != NS_OTR:
+            raise exceptions.ConflictError(_(
+                u"Can't start an OTR session, there is already an encrypted session "
+                u"with {name}").format(name=encrypted_session[u'plugin'].name))
         if not to_jid.resource:
             to_jid.resource = self.host.memory.getMainResource(
                 client, to_jid
@@ -579,6 +588,12 @@
                     ),
                 )
                 client.feedback(from_jid, feedback)
+        except potr.context.NotEncryptedError:
+            msg = D_(u"WARNING: received OTR encrypted data in an unencrypted context")
+            log.warning(msg)
+            feedback = msg
+            client.feedback(from_jid, msg)
+            raise failure.Failure(exceptions.CancelError(msg))
         except StopIteration:
             return data
         else:
@@ -603,11 +618,6 @@
                                                     # frontends, but we don't want it in
                                                     # history
             else:
-                log.warning(
-                    u"An encrypted message was expected, but got {}".format(
-                        data["message"]
-                    )
-                )
                 raise failure.Failure(
                     exceptions.CancelError("Cancelled by OTR")
                 )  # no message at all (no history, no signal)
@@ -646,11 +656,16 @@
         return True
 
     def _sendMessageDataTrigger(self, client, mess_data):
-        if not "OTR" in mess_data:
+        encryption = mess_data.get(C.MESS_KEY_ENCRYPTION)
+        if encryption is None or encryption['plugin'].namespace != NS_OTR:
             return
-        otrctx = mess_data["OTR"]
+        to_jid = mess_data['to']
+        if not to_jid.resource:
+            to_jid.resource = self.host.memory.getMainResource(
+                client, to_jid
+            )  # FIXME: temporary and unsecure, must be changed when frontends
+        otrctx = client._otr_context_manager.getContextForUser(to_jid)
         message_elt = mess_data["xml"]
-        to_jid = mess_data["to"]
         if otrctx.state == potr.context.STATE_ENCRYPTED:
             log.debug(u"encrypting message")
             body = None
@@ -668,6 +683,9 @@
                 log.warning(u"No message found")
             else:
                 self._p_carbons.setPrivate(message_elt)
+                self._p_hints.addHintElements(message_elt, [
+                    self._p_hints.HINT_NO_COPY,
+                    self._p_hints.HINT_NO_PERMANENT_STORE])
                 otrctx.sendMessage(0, unicode(body).encode("utf-8"), appdata=mess_data)
         else:
             feedback = D_(
@@ -689,6 +707,10 @@
             return True
 
         to_jid = copy.copy(mess_data["to"])
+        if client.encryption.getSession(to_jid.userhostJID()):
+            # there is already an encrypted session with this entity
+            return True
+
         if not to_jid.resource:
             to_jid.resource = self.host.memory.getMainResource(
                 client, to_jid
@@ -697,10 +719,8 @@
         otrctx = client._otr_context_manager.getContextForUser(to_jid)
 
         if otrctx.state != potr.context.STATE_PLAINTEXT:
-            self._p_hints.addHint(mess_data, self._p_hints.HINT_NO_COPY)
-            self._p_hints.addHint(mess_data, self._p_hints.HINT_NO_PERMANENT_STORE)
-            mess_data["OTR"] = (otrctx)  #  this indicate that encryption is needed in
-                                         #  sendMessageData trigger
+            client.encryption.start(to_jid, NS_OTR)
+            client.encryption.setEncryptionFlag(mess_data)
             if not mess_data["to"].resource:
                 # if not resource was given, we force it here
                 mess_data["to"] = to_jid