From 494ae444b6710ad95a5ddb0b32d77bfc34c325a5 Mon Sep 17 00:00:00 2001 From: Yann Leboulanger Date: Fri, 15 Feb 2008 10:11:17 +0000 Subject: [PATCH] ability to ignore SSL errors until certificate changes. Fixes #3710 --- src/common/config.py | 1 + src/common/connection.py | 3 +- src/dialogs.py | 61 ++++++++++++++++++++++++++++++++++++++++ src/gajim.py | 25 +++++++++++----- 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/common/config.py b/src/common/config.py index a8a0e6603..e1cd1aced 100644 --- a/src/common/config.py +++ b/src/common/config.py @@ -285,6 +285,7 @@ class Config: 'connection_types': [ opt_str, 'tls ssl plain', _('Ordered list (space separated) of connection type to try. Can contain tls, ssl or plain')], 'warn_when_insecure_connection': [ opt_bool, True, _('Show a warning dialog before sending password on an insecure connection.') ], 'ssl_fingerprint_sha1': [ opt_str, '', '', True ], + 'ignore_ssl_errors': [ opt_str, '', _('Space separated list of ssl errors to ignore.') ], 'use_srv': [ opt_bool, True, '', True ], 'use_custom_host': [ opt_bool, False, '', True ], 'custom_port': [ opt_int, 5222, '', True ], diff --git a/src/common/connection.py b/src/common/connection.py index 2c1177bbc..669f11619 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -618,7 +618,8 @@ class Connection(ConnectionHandlers): errnum = con.Connection.ssl_errnum except AttributeError: errnum = -1 # we don't have an errnum - if errnum > 0: + if errnum > 0 and str(errnum) not in gajim.config.get_per('accounts', + self.name, 'ignore_ssl_errors'): text = _('The authenticity of the %s certificate could be invalid.') %\ hostname if errnum in ssl_error: diff --git a/src/dialogs.py b/src/dialogs.py index 15baf1112..90b9aac42 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -1305,6 +1305,67 @@ class ConfirmationDialogCheck(ConfirmationDialog): ''' Get active state of the checkbutton ''' return self.checkbutton.get_active() +class ConfirmationDialogDubbleCheck(ConfirmationDialog): + '''HIG compliant confirmation dialog with 2 checkbuttons.''' + def __init__(self, pritext, sectext='', checktext1 = '', checktext2 = '', + on_response_ok = None, on_response_cancel = None, is_modal = True): + self.user_response_ok = on_response_ok + self.user_response_cancel = on_response_cancel + + HigDialog.__init__(self, None, gtk.MESSAGE_QUESTION, + gtk.BUTTONS_OK_CANCEL, pritext, sectext, self.on_response_ok, + self.on_response_cancel) + + self.set_default_response(gtk.RESPONSE_OK) + + ok_button = self.action_area.get_children()[0] # right to left + ok_button.grab_focus() + + if checktext1: + self.checkbutton1 = gtk.CheckButton(checktext1) + self.vbox.pack_start(self.checkbutton1, expand = False, fill = True) + else: + self.checkbutton1 = None + if checktext2: + self.checkbutton2 = gtk.CheckButton(checktext2) + self.vbox.pack_start(self.checkbutton2, expand = False, fill = True) + else: + self.checkbutton2 = None + + self.set_modal(is_modal) + self.popup() + + # XXX should cancel if somebody closes the dialog + + def on_response_ok(self, widget): + if self.user_response_ok: + if isinstance(self.user_response_ok, tuple): + self.user_response_ok[0](self.is_checked(), + *self.user_response_ok[1:]) + else: + self.user_response_ok(self.is_checked()) + self.destroy() + + def on_response_cancel(self, widget): + if self.user_response_cancel: + if isinstance(self.user_response_cancel, tuple): + self.user_response_cancel[0](*self.user_response_cancel[1:]) + else: + self.user_response_cancel() + self.destroy() + + def is_checked(self): + ''' Get active state of the checkbutton ''' + if self.checkbutton1: + is_checked_1 = self.checkbutton1.get_active() + else: + is_checked_1 = False + if self.checkbutton2: + is_checked_2 = self.checkbutton2.get_active() + else: + is_checked_2 = False + return [is_checked_1, is_checked_2] + class FTOverwriteConfirmationDialog(ConfirmationDialog): '''HIG compliant confirmation dialog to overwrite or resume a file transfert''' def __init__(self, pritext, sectext='', propose_resume=True): diff --git a/src/gajim.py b/src/gajim.py index 7258df5f1..34faa88f6 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -2218,8 +2218,9 @@ class Interface: def handle_event_ssl_error(self, account, data): # ('SSL_ERROR', account, (text, errnum, cert, sha1_fingerprint)) server = gajim.config.get_per('accounts', account, 'hostname') - def on_ok(is_checked=False): - if is_checked: + + def on_ok(is_checked): + if is_checked[0]: # Check if cert is already in file certs = '' if os.path.isfile(gajim.MY_CACERTS): @@ -2236,25 +2237,35 @@ class Interface: f.close() gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1', data[3]) + if is_checked[1]: + ignore_ssl_errors = gajim.config.get_per('accounts', account, + 'ignore_ssl_errors').split() + ignore_ssl_errors.append(str(data[1])) + gajim.config.set_per('accounts', account, 'ignore_ssl_errors', + ' '.join(ignore_ssl_errors)) gajim.connections[account].ssl_certificate_accepted() + def on_cancel(): gajim.connections[account].disconnect(on_purpose=True) self.handle_event_status(account, 'offline') + pritext = _('Error verifying SSL certificate') sectext = _('There was an error verifying the SSL certificate of your jabber server: %(error)s\nDo you still want to connect to this server?') % {'error': data[0]} if data[1] in (18, 27): - checktext = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % data[3] - dialogs.ConfirmationDialogCheck(pritext, sectext, checktext, - on_response_ok=on_ok, on_response_cancel=on_cancel) + checktext1 = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % data[3] else: - dialogs.ConfirmationDialog(pritext, sectext, - on_response_ok=on_ok, on_response_cancel=on_cancel) + checktext1 = '' + checktext2 = _('Ignore this error for this certificate.') + dialogs.ConfirmationDialogDubbleCheck(pritext, sectext, checktext1, + checktext2, on_response_ok=on_ok, on_response_cancel=on_cancel) def handle_event_fingerprint_error(self, account, data): # ('FINGERPRINT_ERROR', account, (new_fingerprint,)) def on_yes(is_checked): gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1', data[0]) + # Reset the ignored ssl errors + gajim.config.set_per('accounts', account, 'ignore_ssl_errors', '') gajim.connections[account].ssl_certificate_accepted() def on_no(): gajim.connections[account].disconnect(on_purpose=True)