plugin OTR: authentication management + fixed a bug in setState (due to a wrong docstring in potr.context.getCurrentTrust)

This commit is contained in:
Goffi 2014-08-27 00:23:14 +02:00
commit df69c77ea3
2 changed files with 101 additions and 6 deletions

View file

@ -25,6 +25,7 @@ from sat.core.constants import Const as C
from sat.core.log import getLogger
from sat.core import exceptions
log = getLogger(__name__)
from sat.tools import xml_tools
from twisted.words.protocols.jabber import jid
from twisted.python import failure
from twisted.internet import defer
@ -34,6 +35,7 @@ from sat.memory import persistent
NS_OTR = "otr_plugin"
PRIVATE_KEY = "PRIVATE KEY"
MAIN_MENU = D_('OTR')
AUTH_TXT = D_("To authenticate your correspondent, you need to give your below fingerprint *BY AN EXTERNAL CANAL* (i.e. not in this chat), and check that the one he give you is the same as below. If there is a mismatch, there can be a spy between you !")
DEFAULT_POLICY_FLAGS = {
'ALLOW_V1':False,
@ -54,7 +56,6 @@ PLUGIN_INFO = {
class Context(potr.context.Context):
def __init__(self, host, account, other_jid):
super(Context, self).__init__(account, other_jid)
self.host = host
@ -88,7 +89,7 @@ class Context(potr.context.Context):
feedback = _(u"/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % {'other_jid': self.peer.full()}
elif state == potr.context.STATE_ENCRYPTED:
try:
fingerprint, trusted = self.getCurrentTrust()
trusted = self.getCurrentTrust()
except TypeError:
trusted = False
trusted_str = _(u"trusted") if trusted else _(u"untrusted")
@ -138,6 +139,28 @@ class Account(potr.context.Account):
self.client.otr_data[PRIVATE_KEY] = encrypted_priv_key
d.addCallback(save_encrypted_key)
def loadTrusts(self):
trust_data = self.client.otr_data.get('trust', {})
for jid_, jid_data in trust_data.iteritems():
for fingerprint, trust_level in jid_data.iteritems():
log.debug('setting trust for {jid}: [{fingerprint}] = "{trust_level}"'.format(jid=jid_, fingerprint=fingerprint, trust_level=trust_level))
self.trusts.setdefault(jid.JID(jid_), {})[fingerprint] = trust_level
def saveTrusts(self):
log.debug("saving trusts for {profile}".format(profile=self.client.profile))
log.debug("trusts = {}".format(self.client.otr_data['trust']))
self.client.otr_data.force('trust')
def setTrust(self, other_jid, fingerprint, trustLevel):
try:
trust_data = self.client.otr_data['trust']
except KeyError:
trust_data = {}
self.client.otr_data['trust'] = trust_data
jid_data = trust_data.setdefault(other_jid.full(), {})
jid_data[fingerprint] = trustLevel
super(Account, self).setTrust(other_jid, fingerprint, trustLevel)
class ContextManager(object):
@ -169,6 +192,7 @@ class OTR(object):
host.trigger.add("sendMessage", self.sendMessageTrigger, priority=100000)
host.importMenu((MAIN_MENU, D_("Start/Refresh")), self._startRefresh, security_limit=0, help_string=D_("Start or refresh an OTR session"), type_=C.MENU_SINGLE)
host.importMenu((MAIN_MENU, D_("End session")), self._endSession, security_limit=0, help_string=D_("Finish an OTR session"), type_=C.MENU_SINGLE)
host.importMenu((MAIN_MENU, D_("Authenticate")), self._authenticate, security_limit=0, help_string=D_("Authenticate user/see your fingerprint"), type_=C.MENU_SINGLE)
def _fixPotr(self):
# FIXME: potr fix for bad unicode handling
@ -189,7 +213,7 @@ class OTR(object):
@defer.inlineCallbacks
def profileConnected(self, profile):
client = self.host.getClient(profile)
self.context_managers[profile] = ContextManager(self.host, client)
ctxMng = self.context_managers[profile] = ContextManager(self.host, client)
client.otr_data = persistent.PersistentBinaryDict(NS_OTR, profile)
yield client.otr_data.load()
encrypted_priv_key = client.otr_data.get(PRIVATE_KEY, None)
@ -198,6 +222,7 @@ class OTR(object):
client.otr_priv_key = potr.crypt.PK.parsePrivateKey(priv_key.decode('hex'))[0]
else:
client.otr_priv_key = None
ctxMng.account.loadTrusts()
def _startRefresh(self, menu_data, profile):
"""Start or refresh an OTR session
@ -234,6 +259,76 @@ class OTR(object):
otrctx.disconnect()
return {}
def _authenticate(self, menu_data, profile):
"""Authenticate other user and see our own fingerprint
@param menu_data: %(menu_data)s
@param profile: %(doc_profile)s
"""
try:
to_jid = jid.JID(menu_data['jid'])
if not to_jid.resource:
to_jid.resource = self.host.memory.getLastResource(to_jid, profile) # FIXME: temporary and unsecure, must be changed when frontends are refactored
except KeyError:
log.error(_("jid key is not present !"))
return defer.fail(exceptions.DataError)
otrctx = self.context_managers[profile].getContextForUser(to_jid)
priv_key = otrctx.user.client.otr_priv_key
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: _("You have no private key yet, start an OTR conversation to have one"),
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_WARNING
},
title = _("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: _("Your fingerprint is\n{fingerprint}\n\nStart an OTR conversation to have your correspondent one.").format(fingerprint=priv_key),
C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_INFO
},
title = _("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('verified')
note_msg = _("Your correspondant {correspondent} is now TRUSTED")
else:
otrctx.setCurrentTrust('')
note_msg = _("Your correspondant {correspondent} is now UNTRUSTED")
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.user.name)}
)
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(_("Your own fingerprint is:\n{fingerprint}").format(fingerprint=priv_key))
xmlui.addText(_("Your correspondent fingerprint should be:\n{fingerprint}").format(fingerprint=other_fingerprint))
xmlui.addDivider('blank')
xmlui.changeContainer('pairs')
xmlui.addLabel(_('Is your correspondent fingerprint the same as here ?'))
xmlui.addList("match", [('yes', _('yes')),('no', _('no'))], ['yes' if trusted else 'no'])
return {'xmlui': xmlui.toXml()}
def _receivedTreatment(self, data, profile):
from_jid = jid.JID(data['from'])
log.debug(u"_receivedTreatment [from_jid = %s]" % from_jid)

View file

@ -740,9 +740,9 @@ class ListWidget(InputWidget):
"""
@param xmlui
@param options (list[string, tuple]): each option can be given as:
- a string if the label and the value are the same
- a couple if the label and the value differ
@param options (list[option]): each option can be given as:
- a single string if the label and the value are the same
- a tuple with a couple of string (value,label) if the label and the value differ
@param selected (list[string]): list of the selected values
@param style (string)
@param name (string)