Mercurial > libervia-backend
diff sat/memory/encryption.py @ 2743:da59ff099b32
core (memory/encryption), plugin OTR: finished OTR integration in encryption:
- messageEncryptionStart and messageEncryptionStop are now async
- an encryption plugin can now have a startEncryption and endEncryption method, which are called automatically when suitable
- trust is now put in "trusted" key of message_data, and markAsTrusted has been added, it is used in OTR
- getTrustUI implemented for OTR, using legacy authenticate code
- catch potr.crypt.InvalidParameterError on decryption
- fixed some service OTR messages which were not correctly marked as not for storing, and thus were added to MAM archive/carbon copied
- other bug fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 03 Jan 2019 21:00:00 +0100 |
parents | e347e32aa07f |
children | 4b8271399f67 |
line wrap: on
line diff
--- a/sat/memory/encryption.py Thu Jan 03 20:51:08 2019 +0100 +++ b/sat/memory/encryption.py Thu Jan 03 21:00:00 2019 +0100 @@ -22,9 +22,13 @@ from sat.core import exceptions from collections import namedtuple from sat.core.log import getLogger +from sat.tools.common import data_format +from twisted.internet import defer +from twisted.python import failure +import copy log = getLogger(__name__) -from sat.tools.common import data_format +log = getLogger(__name__) EncryptionPlugin = namedtuple("EncryptionPlugin", ("instance", "name", @@ -54,6 +58,12 @@ - getTrustUI(entity): return a XMLUI for trust management entity(jid.JID): entity to manage The returned XMLUI must be a form + if may have the following methods: + - startEncryption(entity): start encrypted session + entity(jid.JID): entity to start encrypted session with + - stopEncryption(entity): start encrypted session + entity(jid.JID): entity to stop encrypted session with + if they don't exists, those 2 methods will be ignored. @param name(unicode): human readable name of the encryption algorithm @param namespace(unicode): namespace of the encryption algorithm @@ -125,6 +135,39 @@ return data_format.serialise(bridge_data) + def _startEncryption(self, plugin, entity): + """Start encryption with a plugin + + This method must be called just before adding a plugin session. + StartEncryptionn method of plugin will be called if it exists. + """ + try: + start_encryption = plugin.instance.startEncryption + except AttributeError: + log.debug(u"No startEncryption method found for {plugin}".format( + plugin = plugin.namespace)) + return defer.succeed(None) + else: + # we copy entity to avoid having the resource changed by stop_encryption + return defer.maybeDeferred(start_encryption, self.client, copy.copy(entity)) + + def _stopEncryption(self, plugin, entity): + """Stop encryption with a plugin + + This method must be called just before removing a plugin session. + StopEncryptionn method of plugin will be called if it exists. + """ + try: + stop_encryption = plugin.instance.stopEncryption + except AttributeError: + log.debug(u"No stopEncryption method found for {plugin}".format( + plugin = plugin.namespace)) + return defer.succeed(None) + else: + # we copy entity to avoid having the resource changed by stop_encryption + return defer.maybeDeferred(stop_encryption, self.client, copy.copy(entity)) + + @defer.inlineCallbacks def start(self, entity, namespace=None, replace=False): """Start an encryption session with an entity @@ -148,7 +191,7 @@ bare_jid = entity.userhostJID() if bare_jid in self._sessions: # we have already an encryption session with this contact - former_plugin = self._sessions[bare_jid]['plugin'] + former_plugin = self._sessions[bare_jid][u"plugin"] if former_plugin.namespace == namespace: log.info(_(u"Session with {bare_jid} is already encrypted with {name}. " u"Nothing to do.").format( @@ -159,6 +202,7 @@ # there is a conflict, but replacement is requested # so we stop previous encryption to use new one del self._sessions[bare_jid] + yield self._stopEncryption(former_plugin, entity) else: msg = (_(u"Session with {bare_jid} is already encrypted with {name}. " u"Please stop encryption session before changing algorithm.") @@ -182,6 +226,7 @@ elif entity.resource: raise ValueError(_(u"{name} encryption must be used with bare jids.")) + yield self._startEncryption(plugin, entity) self._sessions[entity.userhostJID()] = data log.info(_(u"Encryption session has been set for {entity_jid} with " u"{encryption_name}").format( @@ -202,6 +247,7 @@ self.client.feedback(bare_jid, msg) + @defer.inlineCallbacks def stop(self, entity, namespace=None): """Stop an encryption session with an entity @@ -212,8 +258,9 @@ """ session = self.getSession(entity.userhostJID()) if not session: - raise exceptions.NotFound(_(u"There is no encryption session with this " - u"entity.")) + raise failure.Failure( + exceptions.NotFound(_(u"There is no encryption session with this " + u"entity."))) plugin = session['plugin'] if namespace is not None and plugin.namespace != namespace: raise exceptions.InternalError(_( @@ -237,9 +284,16 @@ u"entity.")) else: if not directed_devices: - del session[u'directed_devices'] + # if we have no more directed device sessions, + # we stop the whole session + # see comment below for deleting session before stopping encryption + del self._sessions[entity.userhostJID()] + yield self._stopEncryption(plugin, entity) else: - del self._sessions[entity] + # plugin's stopEncryption may call stop again (that's the case with OTR) + # so we need to remove plugin from session before calling self._stopEncryption + del self._sessions[entity.userhostJID()] + yield self._stopEncryption(plugin, entity) log.info(_(u"encryption session stopped with entity {entity}").format( entity=entity.full())) @@ -296,7 +350,7 @@ raise NotImplementedError( u"Encryption plugin doesn't handle trust management UI") else: - return get_trust_ui(self.client, entity_jid) + return defer.maybeDeferred(get_trust_ui, self.client, entity_jid) ## Triggers ## @@ -324,6 +378,16 @@ mess_data['encrypted'] = True return mess_data + def markAsTrusted(self, mess_data): + """Helper methor to mark a message as sent from a trusted entity. + + This should be used in the post_treat workflow of MessageReceived trigger of + the plugin + @param mess_data(dict): message data as used in post treat workflow + """ + mess_data['trusted'] = True + return mess_data + def markAsUntrusted(self, mess_data): """Helper methor to mark a message as sent from an untrusted entity. @@ -331,5 +395,5 @@ the plugin @param mess_data(dict): message data as used in post treat workflow """ - mess_data['untrusted'] = True + mess_data['trusted'] = False return mess_data