Rework GPG behaviour:
Only encrypt when the receiver is trusted. You have to sign its key or it has to be signed by someone you trust. Fixes #109 Make checkbox insensitive when GPG is disabled on an account (or no passphrase given). Auto assign trusted keys on received presence. Deny encryption on missmatch of assigned key and signing key. Fixes #3376 Do not disable encrypted when receiving an unencrypted message. Print whether a received message was encrypted or not. TODO: Remove togglebutton, its useless now
This commit is contained in:
parent
d17a51c648
commit
6fdd7c0f88
7 changed files with 109 additions and 73 deletions
|
@ -1050,15 +1050,17 @@ class ChatControl(ChatControlBase):
|
||||||
self.on_avatar_eventbox_button_press_event)
|
self.on_avatar_eventbox_button_press_event)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
widget = self.xml.get_widget('gpg_togglebutton')
|
|
||||||
id = widget.connect('clicked', self.on_toggle_gpg_togglebutton)
|
|
||||||
self.handlers[id] = widget
|
|
||||||
|
|
||||||
if self.contact.jid in gajim.encrypted_chats[self.account]:
|
|
||||||
self.xml.get_widget('gpg_togglebutton').set_active(True)
|
|
||||||
|
|
||||||
self.set_session(session)
|
self.set_session(session)
|
||||||
|
|
||||||
|
# Enable ecryption if needed
|
||||||
|
gpg_pref = gajim.config.get_per('contacts', contact.jid,
|
||||||
|
'gpg_enabled')
|
||||||
|
if gpg_pref and gajim.config.get_per('accounts', self.account, 'keyid') and\
|
||||||
|
gajim.connections[self.account].USE_GPG:
|
||||||
|
gajim.encrypted_chats[self.account].append(contact.jid)
|
||||||
|
msg = _('GPG encryption enabled')
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
self.status_tooltip = gtk.Tooltips()
|
self.status_tooltip = gtk.Tooltips()
|
||||||
self.update_ui()
|
self.update_ui()
|
||||||
# restore previous conversation
|
# restore previous conversation
|
||||||
|
@ -1164,8 +1166,6 @@ class ChatControl(ChatControlBase):
|
||||||
gtk.gdk.INTERP_BILINEAR)
|
gtk.gdk.INTERP_BILINEAR)
|
||||||
banner_status_img.set_from_pixbuf(scaled_pix)
|
banner_status_img.set_from_pixbuf(scaled_pix)
|
||||||
|
|
||||||
self._update_gpg()
|
|
||||||
|
|
||||||
def draw_banner_text(self):
|
def draw_banner_text(self):
|
||||||
'''Draw the text in the fat line at the top of the window that
|
'''Draw the text in the fat line at the top of the window that
|
||||||
houses the name, jid.
|
houses the name, jid.
|
||||||
|
@ -1254,34 +1254,26 @@ class ChatControl(ChatControlBase):
|
||||||
# setup the label that holds name and jid
|
# setup the label that holds name and jid
|
||||||
banner_name_label.set_markup(label_text)
|
banner_name_label.set_markup(label_text)
|
||||||
|
|
||||||
def on_toggle_gpg_togglebutton(self, widget):
|
def _toggle_gpg(self):
|
||||||
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
ec = gajim.encrypted_chats[self.account]
|
||||||
widget.get_active())
|
if self.contact.jid in ec:
|
||||||
|
# Disable encryption
|
||||||
def _update_gpg(self):
|
ec.remove(self.contact.jid)
|
||||||
tb = self.xml.get_widget('gpg_togglebutton')
|
gpg_is_active = False
|
||||||
# we can do gpg
|
msg = _('GPG encryption disabled')
|
||||||
# if self.contact is our own contact info (transports),
|
|
||||||
# don't enable pgp
|
|
||||||
if self.contact.keyID and not gajim.jid_is_transport(self.contact.jid):
|
|
||||||
tb.set_sensitive(True)
|
|
||||||
tt = _('OpenPGP Encryption')
|
|
||||||
|
|
||||||
# restore gpg pref
|
|
||||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
|
||||||
'gpg_enabled')
|
|
||||||
if gpg_pref == None:
|
|
||||||
gajim.config.add_per('contacts', self.contact.jid)
|
|
||||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
|
||||||
'gpg_enabled')
|
|
||||||
tb.set_active(gpg_pref)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
tb.set_sensitive(False)
|
# Enable encryption
|
||||||
#we talk about a contact here
|
ec.append(self.contact.jid)
|
||||||
tt = _('%s has not broadcast an OpenPGP key, nor has one been assigned') %\
|
gpg_is_active = True
|
||||||
self.contact.get_shown_name()
|
msg = _('GPG encryption enabled')
|
||||||
gtk.Tooltips().set_tip(self.xml.get_widget('gpg_eventbox'), tt)
|
|
||||||
|
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
||||||
|
'gpg_enabled')
|
||||||
|
if gpg_pref is None:
|
||||||
|
gajim.config.add_per('contacts', self.contact.jid)
|
||||||
|
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
||||||
|
gpg_is_active)
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
def _process_command(self, message):
|
def _process_command(self, message):
|
||||||
if message[0] != '/':
|
if message[0] != '/':
|
||||||
|
@ -1369,9 +1361,13 @@ class ChatControl(ChatControlBase):
|
||||||
encrypted = bool(self.session) and self.session.enable_encryption
|
encrypted = bool(self.session) and self.session.enable_encryption
|
||||||
|
|
||||||
keyID = ''
|
keyID = ''
|
||||||
if self.xml.get_widget('gpg_togglebutton').get_active():
|
gpg_pref = gajim.config.get_per('contacts', contact.jid,
|
||||||
|
'gpg_enabled')
|
||||||
|
if gpg_pref:
|
||||||
keyID = contact.keyID
|
keyID = contact.keyID
|
||||||
encrypted = True
|
encrypted = True
|
||||||
|
if keyID == '':
|
||||||
|
keyID = 'UNKNOWN'
|
||||||
|
|
||||||
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
|
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
|
||||||
'disabled'
|
'disabled'
|
||||||
|
@ -1401,7 +1397,7 @@ class ChatControl(ChatControlBase):
|
||||||
gobject.source_remove(self.possible_paused_timeout_id)
|
gobject.source_remove(self.possible_paused_timeout_id)
|
||||||
gobject.source_remove(self.possible_inactive_timeout_id)
|
gobject.source_remove(self.possible_inactive_timeout_id)
|
||||||
self._schedule_activity_timers()
|
self._schedule_activity_timers()
|
||||||
|
|
||||||
if not ChatControlBase.send_message(self, message, keyID, type = 'chat',
|
if not ChatControlBase.send_message(self, message, keyID, type = 'chat',
|
||||||
chatstate = chatstate_to_send, composing_xep = composing_xep,
|
chatstate = chatstate_to_send, composing_xep = composing_xep,
|
||||||
process_command = process_command):
|
process_command = process_command):
|
||||||
|
@ -1512,17 +1508,14 @@ class ChatControl(ChatControlBase):
|
||||||
# GPG encryption
|
# GPG encryption
|
||||||
ec = gajim.encrypted_chats[self.account]
|
ec = gajim.encrypted_chats[self.account]
|
||||||
if encrypted and jid not in ec:
|
if encrypted and jid not in ec:
|
||||||
msg = _('OpenPGP Encryption enabled')
|
msg = _('The following message was encrypted')
|
||||||
ChatControlBase.print_conversation_line(self, msg,
|
ChatControlBase.print_conversation_line(self, msg,
|
||||||
'status', '', tim)
|
'status', '', tim)
|
||||||
ec.append(jid)
|
self._toggle_gpg()
|
||||||
elif not encrypted and jid in ec:
|
elif not encrypted and jid in ec:
|
||||||
msg = _('OpenPGP Encryption disabled')
|
msg = _('The following message was NOT encrypted')
|
||||||
ChatControlBase.print_conversation_line(self, msg,
|
ChatControlBase.print_conversation_line(self, msg,
|
||||||
'status', '', tim)
|
'status', '', tim)
|
||||||
ec.remove(jid)
|
|
||||||
self.xml.get_widget('gpg_togglebutton').set_active(encrypted)
|
|
||||||
|
|
||||||
if not frm:
|
if not frm:
|
||||||
kind = 'incoming'
|
kind = 'incoming'
|
||||||
name = contact.get_shown_name()
|
name = contact.get_shown_name()
|
||||||
|
@ -1649,13 +1642,17 @@ class ChatControl(ChatControlBase):
|
||||||
|
|
||||||
contact = self.parent_win.get_active_contact()
|
contact = self.parent_win.get_active_contact()
|
||||||
jid = contact.jid
|
jid = contact.jid
|
||||||
|
|
||||||
# check if gpg capabitlies or else make gpg toggle insensitive
|
# check if we support and use gpg
|
||||||
gpg_btn = self.xml.get_widget('gpg_togglebutton')
|
if not gajim.config.get_per('accounts', self.account, 'keyid') or\
|
||||||
isactive = gpg_btn.get_active()
|
not gajim.connections[self.account].USE_GPG or\
|
||||||
is_sensitive = gpg_btn.get_property('sensitive')
|
gajim.jid_is_transport(jid):
|
||||||
toggle_gpg_menuitem.set_active(isactive)
|
toggle_gpg_menuitem.set_sensitive(False)
|
||||||
toggle_gpg_menuitem.set_property('sensitive', is_sensitive)
|
else:
|
||||||
|
toggle_gpg_menuitem.set_sensitive(True)
|
||||||
|
gpg_pref = gajim.config.get_per('contacts', jid,
|
||||||
|
'gpg_enabled')
|
||||||
|
toggle_gpg_menuitem.set_active(bool(gpg_pref))
|
||||||
|
|
||||||
# TODO: check that the remote client supports e2e
|
# TODO: check that the remote client supports e2e
|
||||||
if not gajim.HAVE_PYCRYPTO:
|
if not gajim.HAVE_PYCRYPTO:
|
||||||
|
@ -1694,14 +1691,15 @@ class ChatControl(ChatControlBase):
|
||||||
id = send_file_menuitem.connect('activate',
|
id = send_file_menuitem.connect('activate',
|
||||||
self._on_send_file_menuitem_activate)
|
self._on_send_file_menuitem_activate)
|
||||||
self.handlers[id] = send_file_menuitem
|
self.handlers[id] = send_file_menuitem
|
||||||
id = add_to_roster_menuitem.connect('activate',
|
id = add_to_roster_menuitem.connect('activate',
|
||||||
self._on_add_to_roster_menuitem_activate)
|
self._on_add_to_roster_menuitem_activate)
|
||||||
self.handlers[id] = add_to_roster_menuitem
|
self.handlers[id] = add_to_roster_menuitem
|
||||||
id = toggle_gpg_menuitem.connect('activate',
|
id = toggle_gpg_menuitem.connect('activate',
|
||||||
self._on_toggle_gpg_menuitem_activate)
|
self._on_toggle_gpg_menuitem_activate)
|
||||||
|
self.handlers[id] = toggle_gpg_menuitem
|
||||||
id = toggle_e2e_menuitem.connect('activate',
|
id = toggle_e2e_menuitem.connect('activate',
|
||||||
self._on_toggle_e2e_menuitem_activate)
|
self._on_toggle_e2e_menuitem_activate)
|
||||||
self.handlers[id] = toggle_gpg_menuitem
|
self.handlers[id] = toggle_e2e_menuitem
|
||||||
id = information_menuitem.connect('activate',
|
id = information_menuitem.connect('activate',
|
||||||
self._on_contact_information_menuitem_activate)
|
self._on_contact_information_menuitem_activate)
|
||||||
self.handlers[id] = information_menuitem
|
self.handlers[id] = information_menuitem
|
||||||
|
@ -2154,10 +2152,7 @@ class ChatControl(ChatControlBase):
|
||||||
gajim.interface.roster.on_info(widget, self.contact, self.account)
|
gajim.interface.roster.on_info(widget, self.contact, self.account)
|
||||||
|
|
||||||
def _on_toggle_gpg_menuitem_activate(self, widget):
|
def _on_toggle_gpg_menuitem_activate(self, widget):
|
||||||
# update the button
|
self._toggle_gpg()
|
||||||
# this is reverse logic, as we are on 'activate' (before change happens)
|
|
||||||
tb = self.xml.get_widget('gpg_togglebutton')
|
|
||||||
tb.set_active(not tb.get_active())
|
|
||||||
|
|
||||||
def _on_convert_to_gc_menuitem_activate(self, widget):
|
def _on_convert_to_gc_menuitem_activate(self, widget):
|
||||||
'''user want to invite some friends to chat'''
|
'''user want to invite some friends to chat'''
|
||||||
|
|
|
@ -45,8 +45,6 @@ if gajim.HAVE_GPG:
|
||||||
self.options.armor = 1
|
self.options.armor = 1
|
||||||
self.options.meta_interactive = 0
|
self.options.meta_interactive = 0
|
||||||
self.options.extra_args.append('--no-secmem-warning')
|
self.options.extra_args.append('--no-secmem-warning')
|
||||||
# Nolith's patch - prevent crashs on non fully-trusted keys
|
|
||||||
self.options.extra_args.append('--always-trust')
|
|
||||||
if self.use_agent:
|
if self.use_agent:
|
||||||
self.options.extra_args.append('--use-agent')
|
self.options.extra_args.append('--use-agent')
|
||||||
|
|
||||||
|
@ -173,7 +171,7 @@ if gajim.HAVE_GPG:
|
||||||
|
|
||||||
try: proc.wait()
|
try: proc.wait()
|
||||||
except IOError: pass
|
except IOError: pass
|
||||||
|
|
||||||
keyid = ''
|
keyid = ''
|
||||||
if resp.has_key('GOODSIG'):
|
if resp.has_key('GOODSIG'):
|
||||||
keyid = resp['GOODSIG'].split()[0]
|
keyid = resp['GOODSIG'].split()[0]
|
||||||
|
|
|
@ -961,9 +961,15 @@ class Connection(ConnectionHandlers):
|
||||||
fjid += '/' + resource
|
fjid += '/' + resource
|
||||||
msgtxt = msg
|
msgtxt = msg
|
||||||
msgenc = ''
|
msgenc = ''
|
||||||
|
|
||||||
if keyID and self.USE_GPG:
|
if keyID and self.USE_GPG:
|
||||||
#encrypt
|
if keyID == 'UNKNOWN':
|
||||||
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
error = _('Neither the remote presence is signed, nor a key was assigned.')
|
||||||
|
elif keyID[8:] == 'MISMATCH':
|
||||||
|
error = _('The contact\'s key does not match the key assigned in Gajim.')
|
||||||
|
else:
|
||||||
|
#encrypt
|
||||||
|
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
||||||
if msgenc and not error:
|
if msgenc and not error:
|
||||||
msgtxt = '[This message is encrypted]'
|
msgtxt = '[This message is encrypted]'
|
||||||
lang = os.getenv('LANG')
|
lang = os.getenv('LANG')
|
||||||
|
|
|
@ -2199,6 +2199,7 @@ returns the session that we last sent a message to.'''
|
||||||
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
||||||
#%s is the account name here
|
#%s is the account name here
|
||||||
_('You will be connected to %s without OpenPGP.') % self.name))
|
_('You will be connected to %s without OpenPGP.') % self.name))
|
||||||
|
self.USE_GPG = False
|
||||||
signed = ''
|
signed = ''
|
||||||
self.connected = STATUS_LIST.index(show)
|
self.connected = STATUS_LIST.index(show)
|
||||||
sshow = helpers.get_xmpp_show(show)
|
sshow = helpers.get_xmpp_show(show)
|
||||||
|
|
|
@ -1094,3 +1094,36 @@ def get_transport_path(transport):
|
||||||
return os.path.join(gajim.MY_ICONSETS_PATH, 'transports', transport)
|
return os.path.join(gajim.MY_ICONSETS_PATH, 'transports', transport)
|
||||||
# No transport folder found, use default jabber one
|
# No transport folder found, use default jabber one
|
||||||
return get_iconset_path(gajim.config.get('iconset'))
|
return get_iconset_path(gajim.config.get('iconset'))
|
||||||
|
|
||||||
|
def prepare_and_validate_gpg_keyID(account, jid, keyID):
|
||||||
|
'''Returns an eight char long keyID that can be used with for GPG encryption with this contact.
|
||||||
|
If the given keyID is None, return UNKNOWN; if the key does not match the assigned key
|
||||||
|
XXXXXXXXMISMATCH is returned. If the key is trusted and not yet assigned, assign it'''
|
||||||
|
if gajim.connections[account].USE_GPG:
|
||||||
|
if len(keyID) == 16:
|
||||||
|
keyID = keyID[8:]
|
||||||
|
|
||||||
|
attached_keys = gajim.config.get_per('accounts', account,
|
||||||
|
'attached_gpg_keys').split()
|
||||||
|
|
||||||
|
if jid in attached_keys and keyID:
|
||||||
|
attachedkeyID = attached_keys[attached_keys.index(jid) + 1]
|
||||||
|
if attachedkeyID != keyID:
|
||||||
|
# Mismatch! Another gpg key was expected
|
||||||
|
keyID += 'MISMATCH'
|
||||||
|
elif jid in attached_keys:
|
||||||
|
# An unsigned presence, just use the assigned key
|
||||||
|
keyID = attached_keys[attached_keys.index(jid) + 1]
|
||||||
|
elif keyID:
|
||||||
|
public_keys = gajim.connections[account].ask_gpg_keys()
|
||||||
|
# Assign the corresponding key, if we have it in our keyring
|
||||||
|
if public_keys.has_key(keyID):
|
||||||
|
for u in gajim.contacts.get_contacts(account, jid):
|
||||||
|
u.keyID = keyID
|
||||||
|
keys_str = gajim.config.get_per('accounts', account, 'attached_gpg_keys')
|
||||||
|
keys_str += jid + ' ' + keyID + ' '
|
||||||
|
gajim.config.set_per('accounts', account, 'attached_gpg_keys', keys_str)
|
||||||
|
elif keyID is None:
|
||||||
|
keyID = 'UNKNOWN'
|
||||||
|
return keyID
|
||||||
|
|
||||||
|
|
|
@ -579,10 +579,11 @@ class Interface:
|
||||||
jid = array[0].split('/')[0]
|
jid = array[0].split('/')[0]
|
||||||
keyID = array[5]
|
keyID = array[5]
|
||||||
contact_nickname = array[7]
|
contact_nickname = array[7]
|
||||||
attached_keys = gajim.config.get_per('accounts', account,
|
|
||||||
'attached_gpg_keys').split()
|
# Get the proper keyID
|
||||||
if jid in attached_keys:
|
keyID = helpers.prepare_and_validate_gpg_keyID(account,
|
||||||
keyID = attached_keys[attached_keys.index(jid) + 1]
|
jid, keyID)
|
||||||
|
|
||||||
resource = array[3]
|
resource = array[3]
|
||||||
if not resource:
|
if not resource:
|
||||||
resource = ''
|
resource = ''
|
||||||
|
|
|
@ -1912,12 +1912,11 @@ class RosterWindow:
|
||||||
if keyID[0] == _('None'):
|
if keyID[0] == _('None'):
|
||||||
if contact.jid in keys:
|
if contact.jid in keys:
|
||||||
del keys[contact.jid]
|
del keys[contact.jid]
|
||||||
for u in gajim.contacts.get_contacts(account, contact.jid):
|
keyID = ''
|
||||||
u.keyID = ''
|
|
||||||
else:
|
else:
|
||||||
keys[contact.jid] = keyID[0]
|
keyID = keyID[0]
|
||||||
for u in gajim.contacts.get_contacts(account, contact.jid):
|
keys[contact.jid] = keyID
|
||||||
u.keyID = keyID[0]
|
|
||||||
if gajim.interface.msg_win_mgr.has_window(contact.jid, account):
|
if gajim.interface.msg_win_mgr.has_window(contact.jid, account):
|
||||||
ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account)
|
ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account)
|
||||||
ctrl.update_ui()
|
ctrl.update_ui()
|
||||||
|
@ -1925,6 +1924,9 @@ class RosterWindow:
|
||||||
for jid in keys:
|
for jid in keys:
|
||||||
keys_str += jid + ' ' + keys[jid] + ' '
|
keys_str += jid + ' ' + keys[jid] + ' '
|
||||||
gajim.config.set_per('accounts', account, 'attached_gpg_keys', keys_str)
|
gajim.config.set_per('accounts', account, 'attached_gpg_keys', keys_str)
|
||||||
|
for u in gajim.contacts.get_contacts(account, contact.jid):
|
||||||
|
u.keyID = helpers.prepare_and_validate_gpg_keyID(account,
|
||||||
|
contact.jid, keyID)
|
||||||
|
|
||||||
def update_avatar_in_gui(self, jid, account):
|
def update_avatar_in_gui(self, jid, account):
|
||||||
# Update roster
|
# Update roster
|
||||||
|
|
Loading…
Add table
Reference in a new issue