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
This commit is contained in:
parent
e5e0913aec
commit
09020b7108
5 changed files with 255 additions and 126 deletions
|
|
@ -436,6 +436,7 @@ doc_param_4=extra: optional data that can be used by a plugin to build more spec
|
|||
doc_param_5=%(doc_profile_key)s
|
||||
|
||||
[messageEncryptionStart]
|
||||
async=
|
||||
type=method
|
||||
category=core
|
||||
sig_in=ssbs
|
||||
|
|
@ -451,6 +452,7 @@ doc_param_2=replace: if True and an encryption session already exists, it will b
|
|||
doc_param_3=%(doc_profile_key)s
|
||||
|
||||
[messageEncryptionStop]
|
||||
async=
|
||||
type=method
|
||||
category=core
|
||||
sig_in=ss
|
||||
|
|
|
|||
|
|
@ -423,15 +423,15 @@ class DbusObject(dbus.service.Object):
|
|||
|
||||
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
|
||||
in_signature='ssbs', out_signature='',
|
||||
async_callbacks=None)
|
||||
def messageEncryptionStart(self, to_jid, namespace='', replace=False, profile_key="@NONE@"):
|
||||
return self._callback("messageEncryptionStart", unicode(to_jid), unicode(namespace), replace, unicode(profile_key))
|
||||
async_callbacks=('callback', 'errback'))
|
||||
def messageEncryptionStart(self, to_jid, namespace='', replace=False, profile_key="@NONE@", callback=None, errback=None):
|
||||
return self._callback("messageEncryptionStart", unicode(to_jid), unicode(namespace), replace, unicode(profile_key), callback=callback, errback=errback)
|
||||
|
||||
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
|
||||
in_signature='ss', out_signature='',
|
||||
async_callbacks=None)
|
||||
def messageEncryptionStop(self, to_jid, profile_key):
|
||||
return self._callback("messageEncryptionStop", unicode(to_jid), unicode(profile_key))
|
||||
async_callbacks=('callback', 'errback'))
|
||||
def messageEncryptionStop(self, to_jid, profile_key, callback=None, errback=None):
|
||||
return self._callback("messageEncryptionStop", unicode(to_jid), unicode(profile_key), callback=callback, errback=errback)
|
||||
|
||||
@dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
|
||||
in_signature='sa{ss}a{ss}sa{ss}s', out_signature='',
|
||||
|
|
|
|||
|
|
@ -22,9 +22,13 @@ from sat.core.constants import Const as C
|
|||
from sat.core import exceptions
|
||||
from collections import namedtuple
|
||||
from sat.core.log import getLogger
|
||||
log = getLogger(__name__)
|
||||
from sat.tools.common import data_format
|
||||
from twisted.internet import defer
|
||||
from twisted.python import failure
|
||||
import copy
|
||||
log = getLogger(__name__)
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
EncryptionPlugin = namedtuple("EncryptionPlugin", ("instance",
|
||||
"name",
|
||||
|
|
@ -54,6 +58,12 @@ class EncryptionHandler(object):
|
|||
- 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 @@ class EncryptionHandler(object):
|
|||
|
||||
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 @@ class EncryptionHandler(object):
|
|||
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 @@ class EncryptionHandler(object):
|
|||
# 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 @@ class EncryptionHandler(object):
|
|||
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 @@ class EncryptionHandler(object):
|
|||
|
||||
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 @@ class EncryptionHandler(object):
|
|||
"""
|
||||
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 @@ class EncryptionHandler(object):
|
|||
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 @@ class EncryptionHandler(object):
|
|||
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 @@ class EncryptionHandler(object):
|
|||
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 @@ class EncryptionHandler(object):
|
|||
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
|
||||
|
|
|
|||
|
|
@ -74,9 +74,21 @@ OTR_STATE_ENCRYPTED = "encrypted"
|
|||
|
||||
|
||||
class Context(potr.context.Context):
|
||||
def __init__(self, host, account, other_jid):
|
||||
super(Context, self).__init__(account, other_jid)
|
||||
self.host = host
|
||||
def __init__(self, context_manager, other_jid):
|
||||
self.context_manager = context_manager
|
||||
super(Context, self).__init__(context_manager.account, other_jid)
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self.context_manager.host
|
||||
|
||||
@property
|
||||
def _p_hints(self):
|
||||
return self.context_manager.parent._p_hints
|
||||
|
||||
@property
|
||||
def _p_carbons(self):
|
||||
return self.context_manager.parent._p_carbons
|
||||
|
||||
def getPolicy(self, key):
|
||||
if key in DEFAULT_POLICY_FLAGS:
|
||||
|
|
@ -110,12 +122,42 @@ class Context(potr.context.Context):
|
|||
"timestamp": time.time(),
|
||||
}
|
||||
client.generateMessageXML(mess_data)
|
||||
xml = mess_data[u'xml']
|
||||
self._p_carbons.setPrivate(xml)
|
||||
self._p_hints.addHintElements(xml, [
|
||||
self._p_hints.HINT_NO_COPY,
|
||||
self._p_hints.HINT_NO_PERMANENT_STORE])
|
||||
client.send(mess_data["xml"])
|
||||
else:
|
||||
message_elt = appdata[u"xml"]
|
||||
assert message_elt.name == u"message"
|
||||
message_elt.addElement("body", content=msg)
|
||||
|
||||
def stopCb(self, __, feedback):
|
||||
client = self.user.client
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile
|
||||
)
|
||||
client.feedback(self.peer, feedback)
|
||||
|
||||
def stopEb(self, failure_):
|
||||
# encryption may be already stopped in case of manual stop
|
||||
if not failure_.check(exceptions.NotFound):
|
||||
log.error(u"Error while stopping OTR encryption: {msg}".format(msg=failure_))
|
||||
|
||||
def isTrusted(self):
|
||||
# we have to check value because potr code says that a 2-tuples should be
|
||||
# returned while in practice it's either None or u"trusted"
|
||||
trusted = self.getCurrentTrust()
|
||||
if trusted is None:
|
||||
return False
|
||||
elif trusted == u'trusted':
|
||||
return True
|
||||
else:
|
||||
log.error(u"Unexpected getCurrentTrust() value: {value}".format(
|
||||
value=trusted))
|
||||
return False
|
||||
|
||||
def setState(self, state):
|
||||
client = self.user.client
|
||||
old_state = self.state
|
||||
|
|
@ -123,17 +165,17 @@ class Context(potr.context.Context):
|
|||
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()
|
||||
}
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile
|
||||
)
|
||||
d = client.encryption.stop(self.peer, NS_OTR)
|
||||
d.addCallback(self.stopCb, feedback=feedback)
|
||||
d.addErrback(self.stopEb)
|
||||
return
|
||||
elif state == potr.context.STATE_ENCRYPTED:
|
||||
client.encryption.start(self.peer, NS_OTR)
|
||||
try:
|
||||
trusted = self.getCurrentTrust()
|
||||
trusted = self.isTrusted()
|
||||
except TypeError:
|
||||
trusted = False
|
||||
trusted_str = _(u"trusted") if trusted else _(u"untrusted")
|
||||
|
|
@ -155,13 +197,13 @@ class Context(potr.context.Context):
|
|||
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()
|
||||
)
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile
|
||||
)
|
||||
d = client.encryption.stop(self.peer, NS_OTR)
|
||||
d.addCallback(self.stopCb, feedback=feedback)
|
||||
d.addErrback(self.stopEb)
|
||||
return
|
||||
else:
|
||||
log.error(D_(u"Unknown OTR state"))
|
||||
return
|
||||
|
|
@ -240,15 +282,19 @@ class Account(potr.context.Account):
|
|||
|
||||
|
||||
class ContextManager(object):
|
||||
def __init__(self, host, client):
|
||||
self.host = host
|
||||
self.account = Account(host, client)
|
||||
def __init__(self, parent, client):
|
||||
self.parent = parent
|
||||
self.account = Account(parent.host, client)
|
||||
self.contexts = {}
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self.parent.host
|
||||
|
||||
def startContext(self, other_jid):
|
||||
assert isinstance(other_jid, jid.JID)
|
||||
context = self.contexts.setdefault(
|
||||
other_jid, Context(self.host, self.account, other_jid)
|
||||
other_jid, Context(self, other_jid)
|
||||
)
|
||||
return context
|
||||
|
||||
|
|
@ -323,7 +369,7 @@ class OTR(object):
|
|||
def profileConnected(self, client):
|
||||
if client.profile in self.skipped_profiles:
|
||||
return
|
||||
ctxMng = client._otr_context_manager = ContextManager(self.host, client)
|
||||
ctxMng = client._otr_context_manager = ContextManager(self, client)
|
||||
client._otr_data = persistent.PersistentBinaryDict(NS_OTR, client.profile)
|
||||
yield client._otr_data.load()
|
||||
encrypted_priv_key = client._otr_data.get(PRIVATE_KEY, None)
|
||||
|
|
@ -346,6 +392,110 @@ class OTR(object):
|
|||
context.disconnect()
|
||||
del client._otr_context_manager
|
||||
|
||||
# encryption plugin methods
|
||||
|
||||
def startEncryption(self, client, entity_jid):
|
||||
self.startRefresh(client, entity_jid)
|
||||
|
||||
def stopEncryption(self, client, entity_jid):
|
||||
self.endSession(client, entity_jid)
|
||||
|
||||
def getTrustUI(self, client, entity_jid):
|
||||
if not entity_jid.resource:
|
||||
entity_jid.resource = self.host.memory.getMainResource(
|
||||
client, entity_jid
|
||||
) # FIXME: temporary and unsecure, must be changed when frontends
|
||||
# are refactored
|
||||
ctxMng = client._otr_context_manager
|
||||
otrctx = ctxMng.getContextForUser(entity_jid)
|
||||
priv_key = ctxMng.account.privkey
|
||||
|
||||
if priv_key is None:
|
||||
# we have no private key yet
|
||||
dialog = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE,
|
||||
C.XMLUI_DATA_MESS: _(
|
||||
u"You have no private key yet, start an OTR conversation to "
|
||||
u"have one"
|
||||
),
|
||||
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_WARNING,
|
||||
},
|
||||
title=_(u"No private key"),
|
||||
)
|
||||
return dialog
|
||||
|
||||
other_fingerprint = otrctx.getCurrentKey()
|
||||
|
||||
if other_fingerprint is None:
|
||||
# we have a private key, but not the fingerprint of our correspondent
|
||||
dialog = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE,
|
||||
C.XMLUI_DATA_MESS: _(
|
||||
u"Your fingerprint is:\n{fingerprint}\n\n"
|
||||
u"Start an OTR conversation to have your correspondent one."
|
||||
).format(fingerprint=priv_key),
|
||||
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_INFO,
|
||||
},
|
||||
title=_(u"Fingerprint"),
|
||||
)
|
||||
return dialog
|
||||
|
||||
def setTrust(raw_data, profile):
|
||||
if xml_tools.isXMLUICancelled(raw_data):
|
||||
return {}
|
||||
# This method is called when authentication form is submited
|
||||
data = xml_tools.XMLUIResult2DataFormResult(raw_data)
|
||||
if data["match"] == "yes":
|
||||
otrctx.setCurrentTrust(OTR_STATE_TRUSTED)
|
||||
note_msg = _(u"Your correspondent {correspondent} is now TRUSTED")
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_TRUSTED, entity_jid.full(), client.profile
|
||||
)
|
||||
else:
|
||||
otrctx.setCurrentTrust("")
|
||||
note_msg = _(u"Your correspondent {correspondent} is now UNTRUSTED")
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_UNTRUSTED, entity_jid.full(), client.profile
|
||||
)
|
||||
note = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE,
|
||||
C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer),
|
||||
},
|
||||
)
|
||||
return {"xmlui": note.toXml()}
|
||||
|
||||
submit_id = self.host.registerCallback(setTrust, with_data=True, one_shot=True)
|
||||
trusted = otrctx.isTrusted()
|
||||
|
||||
xmlui = xml_tools.XMLUI(
|
||||
C.XMLUI_FORM,
|
||||
title=_(u"Authentication ({entity_jid})").format(entity_jid=entity_jid.full()),
|
||||
submit_id=submit_id,
|
||||
)
|
||||
xmlui.addText(_(AUTH_TXT))
|
||||
xmlui.addDivider()
|
||||
xmlui.addText(
|
||||
D_(u"Your own fingerprint is:\n{fingerprint}").format(fingerprint=priv_key)
|
||||
)
|
||||
xmlui.addText(
|
||||
D_(u"Your correspondent fingerprint should be:\n{fingerprint}").format(
|
||||
fingerprint=other_fingerprint
|
||||
)
|
||||
)
|
||||
xmlui.addDivider("blank")
|
||||
xmlui.changeContainer("pairs")
|
||||
xmlui.addLabel(D_(u"Is your correspondent fingerprint the same as here ?"))
|
||||
xmlui.addList(
|
||||
"match", [("yes", _("yes")), ("no", _("no"))], ["yes" if trusted else "no"]
|
||||
)
|
||||
return xmlui
|
||||
|
||||
def _otrStartRefresh(self, menu_data, profile):
|
||||
"""Start or refresh an OTR session
|
||||
|
||||
|
|
@ -422,97 +572,7 @@ class OTR(object):
|
|||
|
||||
def authenticate(self, client, to_jid):
|
||||
"""Authenticate other user and see our own fingerprint"""
|
||||
if not to_jid.resource:
|
||||
to_jid.resource = self.host.memory.getMainResource(
|
||||
client, to_jid
|
||||
) # FIXME: temporary and unsecure, must be changed when frontends
|
||||
# are refactored
|
||||
ctxMng = client._otr_context_manager
|
||||
otrctx = ctxMng.getContextForUser(to_jid)
|
||||
priv_key = ctxMng.account.privkey
|
||||
|
||||
if priv_key is None:
|
||||
# we have no private key yet
|
||||
dialog = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE,
|
||||
C.XMLUI_DATA_MESS: _(
|
||||
u"You have no private key yet, start an OTR conversation to "
|
||||
u"have one"
|
||||
),
|
||||
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_WARNING,
|
||||
},
|
||||
title=_(u"No private key"),
|
||||
)
|
||||
return {"xmlui": dialog.toXml()}
|
||||
|
||||
other_fingerprint = otrctx.getCurrentKey()
|
||||
|
||||
if other_fingerprint is None:
|
||||
# we have a private key, but not the fingerprint of our correspondent
|
||||
dialog = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE,
|
||||
C.XMLUI_DATA_MESS: _(
|
||||
u"Your fingerprint is:\n{fingerprint}\n\n"
|
||||
u"Start an OTR conversation to have your correspondent one."
|
||||
).format(fingerprint=priv_key),
|
||||
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_INFO,
|
||||
},
|
||||
title=_(u"Fingerprint"),
|
||||
)
|
||||
return {"xmlui": dialog.toXml()}
|
||||
|
||||
def setTrust(raw_data, profile):
|
||||
# This method is called when authentication form is submited
|
||||
data = xml_tools.XMLUIResult2DataFormResult(raw_data)
|
||||
if data["match"] == "yes":
|
||||
otrctx.setCurrentTrust(OTR_STATE_TRUSTED)
|
||||
note_msg = _(u"Your correspondent {correspondent} is now TRUSTED")
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_TRUSTED, to_jid.full(), client.profile
|
||||
)
|
||||
else:
|
||||
otrctx.setCurrentTrust("")
|
||||
note_msg = _(u"Your correspondent {correspondent} is now UNTRUSTED")
|
||||
self.host.bridge.otrState(
|
||||
OTR_STATE_UNTRUSTED, to_jid.full(), client.profile
|
||||
)
|
||||
note = xml_tools.XMLUI(
|
||||
C.XMLUI_DIALOG,
|
||||
dialog_opt={
|
||||
C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE,
|
||||
C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer),
|
||||
},
|
||||
)
|
||||
return {"xmlui": note.toXml()}
|
||||
|
||||
submit_id = self.host.registerCallback(setTrust, with_data=True, one_shot=True)
|
||||
trusted = bool(otrctx.getCurrentTrust())
|
||||
|
||||
xmlui = xml_tools.XMLUI(
|
||||
C.XMLUI_FORM,
|
||||
title=_("Authentication (%s)") % to_jid.full(),
|
||||
submit_id=submit_id,
|
||||
)
|
||||
xmlui.addText(_(AUTH_TXT))
|
||||
xmlui.addDivider()
|
||||
xmlui.addText(
|
||||
D_(u"Your own fingerprint is:\n{fingerprint}").format(fingerprint=priv_key)
|
||||
)
|
||||
xmlui.addText(
|
||||
D_(u"Your correspondent fingerprint should be:\n{fingerprint}").format(
|
||||
fingerprint=other_fingerprint
|
||||
)
|
||||
)
|
||||
xmlui.addDivider("blank")
|
||||
xmlui.changeContainer("pairs")
|
||||
xmlui.addLabel(D_(u"Is your correspondent fingerprint the same as here ?"))
|
||||
xmlui.addList(
|
||||
"match", [("yes", _("yes")), ("no", _("no"))], ["yes" if trusted else "no"]
|
||||
)
|
||||
xmlui = self.getTrustUI(client, to_jid)
|
||||
return {"xmlui": xmlui.toXml()}
|
||||
|
||||
def _dropPrivKey(self, menu_data, profile):
|
||||
|
|
@ -601,6 +661,12 @@ class OTR(object):
|
|||
feedback = msg
|
||||
client.feedback(from_jid, msg)
|
||||
raise failure.Failure(exceptions.CancelError(msg))
|
||||
except potr.crypt.InvalidParameterError as e:
|
||||
msg = D_(u"Error while trying de decrypt OTR message: {msg}".format(msg=e))
|
||||
log.warning(msg)
|
||||
feedback = msg
|
||||
client.feedback(from_jid, msg)
|
||||
raise failure.Failure(exceptions.CancelError(msg))
|
||||
except StopIteration:
|
||||
return data
|
||||
else:
|
||||
|
|
@ -629,6 +695,13 @@ class OTR(object):
|
|||
exceptions.CancelError("Cancelled by OTR")
|
||||
) # no message at all (no history, no signal)
|
||||
client.encryption.markAsEncrypted(data)
|
||||
trusted = otrctx.isTrusted()
|
||||
|
||||
if trusted:
|
||||
client.encryption.markAsTrusted(data)
|
||||
else:
|
||||
client.encryption.markAsUntrusted(data)
|
||||
|
||||
return data
|
||||
|
||||
def _receivedTreatmentForSkippedProfiles(self, data):
|
||||
|
|
|
|||
|
|
@ -562,12 +562,7 @@ class Bridge(object):
|
|||
if errback is None:
|
||||
errback = log.error
|
||||
error_handler = lambda err:errback(dbus_to_bridge_exception(err))
|
||||
kwargs={}
|
||||
if callback is not None:
|
||||
kwargs['timeout'] = const_TIMEOUT
|
||||
kwargs['reply_handler'] = callback
|
||||
kwargs['error_handler'] = error_handler
|
||||
return self.db_core_iface.messageEncryptionStart(to_jid, namespace, replace, profile_key, **kwargs)
|
||||
return self.db_core_iface.messageEncryptionStart(to_jid, namespace, replace, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)
|
||||
|
||||
def messageEncryptionStop(self, to_jid, profile_key, callback=None, errback=None):
|
||||
if callback is None:
|
||||
|
|
@ -576,12 +571,7 @@ class Bridge(object):
|
|||
if errback is None:
|
||||
errback = log.error
|
||||
error_handler = lambda err:errback(dbus_to_bridge_exception(err))
|
||||
kwargs={}
|
||||
if callback is not None:
|
||||
kwargs['timeout'] = const_TIMEOUT
|
||||
kwargs['reply_handler'] = callback
|
||||
kwargs['error_handler'] = error_handler
|
||||
return self.db_core_iface.messageEncryptionStop(to_jid, profile_key, **kwargs)
|
||||
return self.db_core_iface.messageEncryptionStop(to_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)
|
||||
|
||||
def messageSend(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", callback=None, errback=None):
|
||||
if callback is None:
|
||||
|
|
|
|||
Loading…
Reference in a new issue