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:
Stephan Erb 2007-12-29 23:28:27 +00:00
parent d17a51c648
commit 6fdd7c0f88
7 changed files with 109 additions and 73 deletions

View File

@ -1050,15 +1050,17 @@ class ChatControl(ChatControlBase):
self.on_avatar_eventbox_button_press_event)
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)
# 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.update_ui()
# restore previous conversation
@ -1164,8 +1166,6 @@ class ChatControl(ChatControlBase):
gtk.gdk.INTERP_BILINEAR)
banner_status_img.set_from_pixbuf(scaled_pix)
self._update_gpg()
def draw_banner_text(self):
'''Draw the text in the fat line at the top of the window that
houses the name, jid.
@ -1254,34 +1254,26 @@ class ChatControl(ChatControlBase):
# setup the label that holds name and jid
banner_name_label.set_markup(label_text)
def on_toggle_gpg_togglebutton(self, widget):
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
widget.get_active())
def _update_gpg(self):
tb = self.xml.get_widget('gpg_togglebutton')
# we can do gpg
# 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)
def _toggle_gpg(self):
ec = gajim.encrypted_chats[self.account]
if self.contact.jid in ec:
# Disable encryption
ec.remove(self.contact.jid)
gpg_is_active = False
msg = _('GPG encryption disabled')
else:
tb.set_sensitive(False)
#we talk about a contact here
tt = _('%s has not broadcast an OpenPGP key, nor has one been assigned') %\
self.contact.get_shown_name()
gtk.Tooltips().set_tip(self.xml.get_widget('gpg_eventbox'), tt)
# Enable encryption
ec.append(self.contact.jid)
gpg_is_active = True
msg = _('GPG encryption enabled')
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):
if message[0] != '/':
@ -1369,9 +1361,13 @@ class ChatControl(ChatControlBase):
encrypted = bool(self.session) and self.session.enable_encryption
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
encrypted = True
if keyID == '':
keyID = 'UNKNOWN'
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
'disabled'
@ -1401,7 +1397,7 @@ class ChatControl(ChatControlBase):
gobject.source_remove(self.possible_paused_timeout_id)
gobject.source_remove(self.possible_inactive_timeout_id)
self._schedule_activity_timers()
if not ChatControlBase.send_message(self, message, keyID, type = 'chat',
chatstate = chatstate_to_send, composing_xep = composing_xep,
process_command = process_command):
@ -1512,17 +1508,14 @@ class ChatControl(ChatControlBase):
# GPG encryption
ec = gajim.encrypted_chats[self.account]
if encrypted and jid not in ec:
msg = _('OpenPGP Encryption enabled')
msg = _('The following message was encrypted')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
ec.append(jid)
self._toggle_gpg()
elif not encrypted and jid in ec:
msg = _('OpenPGP Encryption disabled')
msg = _('The following message was NOT encrypted')
ChatControlBase.print_conversation_line(self, msg,
'status', '', tim)
ec.remove(jid)
self.xml.get_widget('gpg_togglebutton').set_active(encrypted)
if not frm:
kind = 'incoming'
name = contact.get_shown_name()
@ -1649,13 +1642,17 @@ class ChatControl(ChatControlBase):
contact = self.parent_win.get_active_contact()
jid = contact.jid
# check if gpg capabitlies or else make gpg toggle insensitive
gpg_btn = self.xml.get_widget('gpg_togglebutton')
isactive = gpg_btn.get_active()
is_sensitive = gpg_btn.get_property('sensitive')
toggle_gpg_menuitem.set_active(isactive)
toggle_gpg_menuitem.set_property('sensitive', is_sensitive)
# check if we support and use gpg
if not gajim.config.get_per('accounts', self.account, 'keyid') or\
not gajim.connections[self.account].USE_GPG or\
gajim.jid_is_transport(jid):
toggle_gpg_menuitem.set_sensitive(False)
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
if not gajim.HAVE_PYCRYPTO:
@ -1694,14 +1691,15 @@ class ChatControl(ChatControlBase):
id = send_file_menuitem.connect('activate',
self._on_send_file_menuitem_activate)
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.handlers[id] = add_to_roster_menuitem
id = toggle_gpg_menuitem.connect('activate',
self.handlers[id] = add_to_roster_menuitem
id = toggle_gpg_menuitem.connect('activate',
self._on_toggle_gpg_menuitem_activate)
self.handlers[id] = toggle_gpg_menuitem
id = toggle_e2e_menuitem.connect('activate',
self._on_toggle_e2e_menuitem_activate)
self.handlers[id] = toggle_gpg_menuitem
self.handlers[id] = toggle_e2e_menuitem
id = information_menuitem.connect('activate',
self._on_contact_information_menuitem_activate)
self.handlers[id] = information_menuitem
@ -2154,10 +2152,7 @@ class ChatControl(ChatControlBase):
gajim.interface.roster.on_info(widget, self.contact, self.account)
def _on_toggle_gpg_menuitem_activate(self, widget):
# update the button
# 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())
self._toggle_gpg()
def _on_convert_to_gc_menuitem_activate(self, widget):
'''user want to invite some friends to chat'''

View File

@ -45,8 +45,6 @@ if gajim.HAVE_GPG:
self.options.armor = 1
self.options.meta_interactive = 0
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:
self.options.extra_args.append('--use-agent')
@ -173,7 +171,7 @@ if gajim.HAVE_GPG:
try: proc.wait()
except IOError: pass
keyid = ''
if resp.has_key('GOODSIG'):
keyid = resp['GOODSIG'].split()[0]

View File

@ -961,9 +961,15 @@ class Connection(ConnectionHandlers):
fjid += '/' + resource
msgtxt = msg
msgenc = ''
if keyID and self.USE_GPG:
#encrypt
msgenc, error = self.gpg.encrypt(msg, [keyID])
if keyID == 'UNKNOWN':
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:
msgtxt = '[This message is encrypted]'
lang = os.getenv('LANG')

View File

@ -2199,6 +2199,7 @@ returns the session that we last sent a message to.'''
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
#%s is the account name here
_('You will be connected to %s without OpenPGP.') % self.name))
self.USE_GPG = False
signed = ''
self.connected = STATUS_LIST.index(show)
sshow = helpers.get_xmpp_show(show)

View File

@ -1094,3 +1094,36 @@ def get_transport_path(transport):
return os.path.join(gajim.MY_ICONSETS_PATH, 'transports', transport)
# No transport folder found, use default jabber one
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

View File

@ -579,10 +579,11 @@ class Interface:
jid = array[0].split('/')[0]
keyID = array[5]
contact_nickname = array[7]
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
# Get the proper keyID
keyID = helpers.prepare_and_validate_gpg_keyID(account,
jid, keyID)
resource = array[3]
if not resource:
resource = ''

View File

@ -1912,12 +1912,11 @@ class RosterWindow:
if keyID[0] == _('None'):
if contact.jid in keys:
del keys[contact.jid]
for u in gajim.contacts.get_contacts(account, contact.jid):
u.keyID = ''
keyID = ''
else:
keys[contact.jid] = keyID[0]
for u in gajim.contacts.get_contacts(account, contact.jid):
u.keyID = keyID[0]
keyID = keyID[0]
keys[contact.jid] = keyID
if gajim.interface.msg_win_mgr.has_window(contact.jid, account):
ctrl = gajim.interface.msg_win_mgr.get_control(contact.jid, account)
ctrl.update_ui()
@ -1925,6 +1924,9 @@ class RosterWindow:
for jid in keys:
keys_str += jid + ' ' + keys[jid] + ' '
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):
# Update roster