Commit 88f017a2 authored by Brendan Taylor's avatar Brendan Taylor

realtime notification of esession begin/end

parent 00ad2846
......@@ -1057,10 +1057,7 @@ class ChatControl(ChatControlBase):
if self.contact.jid in gajim.encrypted_chats[self.account]:
self.xml.get_widget('gpg_togglebutton').set_active(True)
self.session = session
# does this window have an existing, active esession?
self.esessioned = False
self.set_session(session)
self.status_tooltip = gtk.Tooltips()
self.update_ui()
......@@ -1467,6 +1464,23 @@ class ChatControl(ChatControlBase):
self.mouse_over_in_last_30_secs = False
self.kbd_activity_in_last_30_secs = False
# print esession settings to textview
def print_esession_details(self):
if self.session and self.session.enable_encryption:
msg = _('E2E encryption enabled')
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
if self.session.loggable:
msg = _('Session WILL be logged')
else:
msg = _('Session WILL NOT be logged')
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
else:
msg = _('E2E encryption disabled')
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
def print_conversation(self, text, frm = '', tim = None,
encrypted = False, subject = None, xhtml = None):
'''Print a line in the conversation:
......@@ -1486,41 +1500,21 @@ class ChatControl(ChatControlBase):
kind = 'info'
name = ''
else:
# ESessions
if self.session and self.session.enable_encryption:
if not self.esessioned:
msg = _('Encryption enabled')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
if self.session.loggable:
msg = _('Session WILL be logged')
else:
msg = _('Session WILL NOT be logged')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
self.esessioned = True
elif not encrypted:
if not encrypted:
msg = _('The following message was NOT encrypted')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
elif self.esessioned:
msg = _('Encryption disabled')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
self.esessioned = False
else:
# GPG encryption
ec = gajim.encrypted_chats[self.account]
if encrypted and jid not in ec:
msg = _('Encryption enabled')
msg = _('OpenPGP Encryption enabled')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
ec.append(jid)
elif not encrypted and jid in ec:
msg = _('Encryption disabled')
msg = _('OpenPGP Encryption disabled')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
ec.remove(jid)
......@@ -2003,12 +1997,16 @@ class ChatControl(ChatControlBase):
def read_queue(self):
'''read queue and print messages containted in it'''
jid = self.contact.jid
jid_with_resource = jid
if self.resource:
jid_with_resource += '/' + self.resource
events = gajim.events.get_events(self.account, jid_with_resource)
if hasattr(self, 'session') and self.session and self.session.enable_encryption:
self.print_esession_details()
# Is it a pm ?
is_pm = False
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
......@@ -2169,18 +2167,18 @@ class ChatControl(ChatControlBase):
msg = _('Encryption disabled')
ChatControlBase.print_conversation_line(self, msg,
'status', '', None)
self.esessioned = False
jid = str(self.session.jid)
gajim.connections[self.account].delete_session(jid,
self.session.thread_id)
self.session = gajim.connections[self.account].make_new_session(jid)
self.set_session(gajim.connections[self.account].make_new_session(jid))
else:
if not self.session:
self.session = gajim.connections[self.account].make_new_session(
self.contact.jid)
fjid = self.contact.get_full_jid()
new_sess = gajim.connections[self.account].make_new_session(fjid)
self.set_session(new_sess)
# XXX decide whether to use 4 or 3 message negotiation
self.session.negotiate_e2e(False)
......
......@@ -71,8 +71,10 @@ class StanzaSession(object):
def cancelled_negotiation(self):
'''A negotiation has been cancelled, so reset this session to its default state.'''
# XXX notify the user
if hasattr(self, 'control'):
msg = _('Session negotiation cancelled')
self.control.print_conversation_line(self, msg, 'status', '', None)
self.status = None
self.negotiated = {}
......@@ -92,7 +94,7 @@ class StanzaSession(object):
self.status = None
def acknowledge_termination(self):
# we could send an acknowledgement message here, but we won't.
# we could send an acknowledgement message to the remote client here
self.status = None
if gajim.HAVE_PYCRYPTO:
......@@ -105,7 +107,7 @@ if gajim.HAVE_PYCRYPTO:
import secrets
# an encrypted stanza negotiation has several states. i've represented them
# as the following values in the 'status'
# as the following values in the 'status'
# attribute of the session object:
# 1. None:
......@@ -143,7 +145,7 @@ class EncryptedStanzaSession(StanzaSession):
# _s denotes 'self' (ie. this client)
self._kc_s = None
# _o denotes 'other' (ie. the client at the other end of the session)
self._kc_o = None
......@@ -161,17 +163,17 @@ class EncryptedStanzaSession(StanzaSession):
self._kc_o = value
self.decrypter = self.cipher.new(self._kc_o, self.cipher.MODE_CTR,
counter=self.decryptcounter)
def get_kc_o(self):
return self._kc_o
kc_s = property(get_kc_s, set_kc_s)
kc_o = property(get_kc_o, set_kc_o)
def encryptcounter(self):
self.c_s = (self.c_s + 1) % (2 ** self.n)
return crypto.encode_mpi_with_padding(self.c_s)
def decryptcounter(self):
self.c_o = (self.c_o + 1) % (2 ** self.n)
return crypto.encode_mpi_with_padding(self.c_o)
......@@ -231,7 +233,7 @@ class EncryptedStanzaSession(StanzaSession):
def decompress(self, compressed):
if self.compression == None:
return compressed
return compressed
def encrypt(self, encryptable):
padded = crypto.pad_to_multiple(encryptable, 16, ' ', False)
......@@ -343,7 +345,7 @@ class EncryptedStanzaSession(StanzaSession):
content += self.form_o + form_o2
mac_o_calculated = self.hmac(self.ks_o, content)
if self.negotiated['recv_pubkey']:
hash = crypto.sha256(mac_o_calculated)
......@@ -380,7 +382,7 @@ class EncryptedStanzaSession(StanzaSession):
if self.negotiated['send_pubkey'] == 'hash':
b64ed = base64.b64encode(self.hash(pubkey_s))
pubkey_s = '<fingerprint>%s</fingerprint>' % b64ed
id_s = self.encrypt(pubkey_s + sign_s)
else:
id_s = self.encrypt(mac_s)
......@@ -395,7 +397,7 @@ class EncryptedStanzaSession(StanzaSession):
if self.sigmai:
# XXX save retained secret?
self.check_identity(lambda : ())
return (xmpp.DataField(name='identity', value=base64.b64encode(id_s)), \
xmpp.DataField(name='mac', value=base64.b64encode(m_s)))
......@@ -437,7 +439,7 @@ class EncryptedStanzaSession(StanzaSession):
x.addChild(node=xmpp.DataField(name='sign_algs', value='http://www.w3.org/2000/09/xmldsig#rsa-sha256', typ='hidden'))
self.n_s = crypto.generate_nonce()
x.addChild(node=xmpp.DataField(name='my_nonce', value=base64.b64encode(self.n_s), typ='hidden'))
modp_options = [ 5, 14, 2, 1 ]
......@@ -454,7 +456,7 @@ class EncryptedStanzaSession(StanzaSession):
self.status = 'requested-e2e'
self.send(request)
# 4.3 esession response (bob)
def verify_options_bob(self, form):
negotiated = {'recv_pubkey': None, 'send_pubkey': None}
......@@ -570,8 +572,8 @@ class EncryptedStanzaSession(StanzaSession):
self.d = crypto.powmod(g, self.y, p)
to_add = { 'my_nonce': self.n_s,
'dhkeys': crypto.encode_mpi(self.d),
'counter': crypto.encode_mpi(self.c_o),
'dhkeys': crypto.encode_mpi(self.d),
'counter': crypto.encode_mpi(self.c_o),
'nonce': self.n_o }
for name in to_add:
......@@ -666,7 +668,7 @@ class EncryptedStanzaSession(StanzaSession):
self.kc_o, self.km_o, self.ks_o = self.generate_responder_keys(self.k)
self.verify_identity(form, self.d, True, 'b')
else:
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped())
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped())
rshashes = [self.hmac(self.n_s, rs) for (rs,v) in srses]
if not rshashes:
......@@ -677,7 +679,7 @@ class EncryptedStanzaSession(StanzaSession):
rshashes = [base64.b64encode(rshash) for rshash in rshashes]
result.addChild(node=xmpp.DataField(name='rshashes', value=rshashes))
result.addChild(node=xmpp.DataField(name='dhkeys', value=base64.b64encode(crypto.encode_mpi(e))))
self.form_o = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
# MUST securely destroy K unless it will be used later to generate the final shared secret
......@@ -687,13 +689,13 @@ class EncryptedStanzaSession(StanzaSession):
feature.addChild(node=result)
self.send(accept)
if self.sigmai:
self.status = 'active'
self.enable_encryption = True
else:
self.status = 'identified-alice'
# 4.5 esession accept (bob)
def accept_e2e_bob(self, form):
response = xmpp.Message()
......@@ -724,7 +726,7 @@ class EncryptedStanzaSession(StanzaSession):
# 4.5.4 generating bob's final session keys
srs = ''
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped())
rshashes = [base64.b64decode(rshash) for rshash in form.getField('rshashes').getValues()]
......@@ -767,6 +769,9 @@ class EncryptedStanzaSession(StanzaSession):
self.status = 'active'
self.enable_encryption = True
if hasattr(self, 'control'):
self.control.print_esession_details()
def final_steps_alice(self, form):
srs = ''
srses = secrets.secrets().retained_secrets(self.conn.name, self.jid.getStripped())
......@@ -793,13 +798,16 @@ class EncryptedStanzaSession(StanzaSession):
self.verify_identity(form, self.d, False, 'b')
# Note: If Alice discovers an error then she SHOULD ignore any encrypted content she received in the stanza.
if self.negotiated['logging'] == 'mustnot':
self.loggable = False
self.status = 'active'
self.enable_encryption = True
if hasattr(self, 'control'):
self.control.print_esession_details()
# calculate and store the new retained secret
# prompt the user to check the remote party's identity (if necessary)
def do_retained_secret(self, k, srs):
......
......@@ -2031,7 +2031,8 @@ class Interface:
ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account)
if ctrl:
ctrl.session = gajim.connections[account].make_new_session(str(jid))
new_sess = gajim.connections[account].make_new_session(str(jid))
ctrl.set_session(new_sess)
return
......@@ -2044,7 +2045,8 @@ class Interface:
contact = gajim.contacts.get_contact(account, str(jid), resource)
if not contact:
connection = gajim.connections[account]
contact = gajim.contacts.create_contact(jid = jid.getStripped(), resource = resource, show = connection.get_status())
contact = gajim.contacts.create_contact(jid = jid.getStripped(),
resource = resource, show = connection.get_status())
self.roster.new_chat(contact, account, resource = resource)
ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account)
......
......@@ -117,15 +117,26 @@ class MessageControl:
return len(gajim.events.get_events(self.account, self.contact.jid))
def set_session(self, session):
if session == self.session:
if hasattr(self, 'session') and session == self.session:
return
if self.session:
was_encrypted = False
if hasattr(self, 'session') and self.session:
if self.session.enable_encryption:
was_encrypted = True
print "starting a new session, dropping the old one!"
gajim.connections[self.account].delete_session(self.session.jid, self.session.thread_id)
self.session = session
if session:
session.control = self
if was_encrypted:
self.print_esession_details()
def send_message(self, message, keyID = '', type = 'chat',
chatstate = None, msg_id = None, composing_xep = None, resource = None,
user_nick = None):
......@@ -134,7 +145,10 @@ class MessageControl:
jid = self.contact.jid
if not self.session:
self.session = gajim.connections[self.account].make_new_session(self.contact.get_full_jid())
fjid = self.contact.get_full_jid()
new_session = gajim.connections[self.account].make_new_session(fjid)
self.set_session(new_session)
# Send and update history
return gajim.connections[self.account].send_message(jid, message, keyID,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment