Philipp Hörist pushed to branch master at gajim / gajim

Commits:

5 changed files:

Changes:

  • gajim/common/config.py
    ... ... @@ -347,8 +347,6 @@ class Config:
    347 347
                         'action_when_plaintext_connection': [ opt_str, 'warn', _('Show a warning dialog before sending password on an plaintext connection. Can be \'warn\', \'connect\', \'disconnect\'') ],
    
    348 348
                         'warn_when_insecure_ssl_connection': [ opt_bool, True, _('Show a warning dialog before using standard SSL library.') ],
    
    349 349
                         'warn_when_insecure_password': [ opt_bool, True, _('Show a warning dialog before sending PLAIN password over a plain connection.') ],
    
    350
    -                    'ssl_fingerprint_sha1': [ opt_str, '', '', True ],
    
    351
    -                    'ssl_fingerprint_sha256': [ opt_str, '', '', True ],
    
    352 350
                         'ignore_ssl_errors': [ opt_str, '', _('Space separated list of ssl errors to ignore.') ],
    
    353 351
                         'use_srv': [ opt_bool, True, '', True ],
    
    354 352
                         'use_custom_host': [ opt_bool, False, '', True ],
    

  • gajim/common/connection.py
    ... ... @@ -1355,82 +1355,64 @@ class Connection(CommonConnection, ConnectionHandlers):
    1355 1355
             log.debug('Connected to server %s:%s with %s' % (
    
    1356 1356
                     self._current_host['host'], self._current_host['port'], con_type))
    
    1357 1357
     
    
    1358
    -        if app.config.get_per('accounts', self.name, 'anonymous_auth'):
    
    1359
    -            name = None
    
    1358
    +        self.connection = con
    
    1359
    +
    
    1360
    +        ssl_errors = con.Connection.ssl_errors
    
    1361
    +        ignored_ssl_errors = self._get_ignored_ssl_errors()
    
    1362
    +        self._ssl_errors = set(ssl_errors) - set(ignored_ssl_errors)
    
    1363
    +        self.process_ssl_errors()
    
    1364
    +
    
    1365
    +    def _get_ignored_ssl_errors(self):
    
    1366
    +        ignore_ssl_errors = app.config.get_per(
    
    1367
    +            'accounts', self.name, 'ignore_ssl_errors').split()
    
    1368
    +        return [int(err) for err in ignore_ssl_errors]
    
    1369
    +
    
    1370
    +    def process_ssl_errors(self):
    
    1371
    +        if not self._ssl_errors:
    
    1372
    +            self.ssl_certificate_accepted()
    
    1373
    +            return
    
    1374
    +
    
    1375
    +        cert = self.connection.Connection.ssl_certificate
    
    1376
    +        errnum = self._ssl_errors.pop()
    
    1377
    +        hostname = app.config.get_per('accounts', self.name, 'hostname')
    
    1378
    +        text = _('The authenticity of the %s '
    
    1379
    +                 'certificate could be invalid') % hostname
    
    1380
    +        if errnum in ssl_error:
    
    1381
    +            text += _('\nSSL Error: <b>%s</b>') % ssl_error[errnum]
    
    1360 1382
             else:
    
    1383
    +            text += _('\nUnknown SSL error: %d') % errnum
    
    1384
    +        fingerprint_sha1 = cert.digest('sha1').decode('utf-8')
    
    1385
    +        fingerprint_sha256 = cert.digest('sha256').decode('utf-8')
    
    1386
    +        pem = OpenSSL.crypto.dump_certificate(
    
    1387
    +            OpenSSL.crypto.FILETYPE_PEM, cert).decode('utf-8')
    
    1388
    +        app.nec.push_incoming_event(
    
    1389
    +            SSLErrorEvent(None, conn=self,
    
    1390
    +                          error_text=text,
    
    1391
    +                          error_num=errnum,
    
    1392
    +                          cert=pem,
    
    1393
    +                          fingerprint_sha1=fingerprint_sha1,
    
    1394
    +                          fingerprint_sha256=fingerprint_sha256,
    
    1395
    +                          certificate=cert))
    
    1396
    +
    
    1397
    +    def ssl_certificate_accepted(self):
    
    1398
    +        if not self.connection:
    
    1399
    +            self.disconnect(on_purpose=True)
    
    1400
    +            app.nec.push_incoming_event(
    
    1401
    +                ConnectionLostEvent(
    
    1402
    +                    None, conn=self,
    
    1403
    +                    title=_('Could not connect to account %s') % self.name,
    
    1404
    +                    msg=_('Connection with account %s has been lost. '
    
    1405
    +                          'Retry connecting.') % self.name))
    
    1406
    +            return
    
    1407
    +
    
    1408
    +        name = None
    
    1409
    +        if not app.config.get_per('accounts', self.name, 'anonymous_auth'):
    
    1361 1410
                 name = app.config.get_per('accounts', self.name, 'name')
    
    1362
    -        hostname = app.config.get_per('accounts', self.name, 'hostname')
    
    1363
    -        self.connection = con
    
    1364
    -        try:
    
    1365
    -            errnum = con.Connection.ssl_errnum
    
    1366
    -        except AttributeError:
    
    1367
    -            errnum = 0
    
    1368
    -        cert = con.Connection.ssl_certificate
    
    1369
    -        if errnum > 0 and str(errnum) not in app.config.get_per('accounts',
    
    1370
    -        self.name, 'ignore_ssl_errors').split():
    
    1371
    -            text = _('The authenticity of the %s certificate could be invalid'
    
    1372
    -                ) % hostname
    
    1373
    -            if errnum in ssl_error:
    
    1374
    -                text += _('\nSSL Error: <b>%s</b>') % ssl_error[errnum]
    
    1375
    -            else:
    
    1376
    -                text += _('\nUnknown SSL error: %d') % errnum
    
    1377
    -            fingerprint_sha1 = cert.digest('sha1').decode('utf-8')
    
    1378
    -            fingerprint_sha256 = cert.digest('sha256').decode('utf-8')
    
    1379
    -            pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
    
    1380
    -                cert).decode('utf-8')
    
    1381
    -            app.nec.push_incoming_event(SSLErrorEvent(None, conn=self,
    
    1382
    -                error_text=text, error_num=errnum, cert=pem,
    
    1383
    -                fingerprint_sha1=fingerprint_sha1,
    
    1384
    -                fingerprint_sha256=fingerprint_sha256, certificate=cert))
    
    1385
    -            return True
    
    1386
    -        if cert:
    
    1387
    -            fingerprint_sha1 = cert.digest('sha1').decode('utf-8')
    
    1388
    -            fingerprint_sha256 = cert.digest('sha256').decode('utf-8')
    
    1389
    -            saved_fingerprint_sha1 = app.config.get_per('accounts', self.name,
    
    1390
    -                'ssl_fingerprint_sha1')
    
    1391
    -            if saved_fingerprint_sha1:
    
    1392
    -                # Check sha1 fingerprint
    
    1393
    -                if fingerprint_sha1 != saved_fingerprint_sha1:
    
    1394
    -                    if not check_X509.check_certificate(cert, hostname):
    
    1395
    -                        app.nec.push_incoming_event(FingerprintErrorEvent(
    
    1396
    -                            None, conn=self, certificate=cert,
    
    1397
    -                            new_fingerprint_sha1=fingerprint_sha1,
    
    1398
    -                            new_fingerprint_sha256=fingerprint_sha256))
    
    1399
    -                        return True
    
    1400
    -            app.config.set_per('accounts', self.name, 'ssl_fingerprint_sha1',
    
    1401
    -                fingerprint_sha1)
    
    1402
    -
    
    1403
    -            saved_fingerprint_sha256 = app.config.get_per('accounts', self.name,
    
    1404
    -                'ssl_fingerprint_sha256')
    
    1405
    -            if saved_fingerprint_sha256:
    
    1406
    -                # Check sha256 fingerprint
    
    1407
    -                if fingerprint_sha256 != saved_fingerprint_sha256:
    
    1408
    -                    if not check_X509.check_certificate(cert, hostname):
    
    1409
    -                        app.nec.push_incoming_event(FingerprintErrorEvent(
    
    1410
    -                            None, conn=self, certificate=cert,
    
    1411
    -                            new_fingerprint_sha1=fingerprint_sha1,
    
    1412
    -                            new_fingerprint_sha256=fingerprint_sha256))
    
    1413
    -                        return True
    
    1414
    -            app.config.set_per('accounts', self.name,
    
    1415
    -                'ssl_fingerprint_sha256', fingerprint_sha256)
    
    1416
    -
    
    1417
    -            if not check_X509.check_certificate(cert, hostname) and \
    
    1418
    -            '100' not in app.config.get_per('accounts', self.name,
    
    1419
    -            'ignore_ssl_errors').split():
    
    1420
    -                pem = OpenSSL.crypto.dump_certificate(
    
    1421
    -                    OpenSSL.crypto.FILETYPE_PEM, cert).decode('utf-8')
    
    1422
    -                txt = _('The authenticity of the %s certificate could be '
    
    1423
    -                    'invalid.\nThe certificate does not cover this domain.') %\
    
    1424
    -                    hostname
    
    1425
    -                app.nec.push_incoming_event(SSLErrorEvent(None, conn=self,
    
    1426
    -                    error_text=txt, error_num=100, cert=pem,
    
    1427
    -                    fingerprint_sha1=fingerprint_sha1,
    
    1428
    -                    fingerprint_sha256=fingerprint_sha256, certificate=cert))
    
    1429
    -                return True
    
    1430 1411
     
    
    1431
    -        self._register_handlers(con, con_type)
    
    1432
    -        auth_mechs = app.config.get_per('accounts', self.name, 'authentication_mechanisms')
    
    1433
    -        auth_mechs = auth_mechs.split()
    
    1412
    +        self._register_handlers(self.connection, self._current_type)
    
    1413
    +
    
    1414
    +        auth_mechs = app.config.get_per(
    
    1415
    +            'accounts', self.name, 'authentication_mechanisms').split()
    
    1434 1416
             for mech in auth_mechs:
    
    1435 1417
                 if mech not in nbxmpp.auth_nb.SASL_AUTHENTICATION_MECHANISMS | set(['XEP-0078']):
    
    1436 1418
                     log.warning("Unknown authentication mechanisms %s" % mech)
    
    ... ... @@ -1438,24 +1420,12 @@ class Connection(CommonConnection, ConnectionHandlers):
    1438 1420
                 auth_mechs = None
    
    1439 1421
             else:
    
    1440 1422
                 auth_mechs = set(auth_mechs)
    
    1441
    -        con.auth(user=name, password=self.password,
    
    1442
    -            resource=self.server_resource, sasl=True, on_auth=self.__on_auth, auth_mechs=auth_mechs)
    
    1443
    -
    
    1444
    -    def ssl_certificate_accepted(self):
    
    1445
    -        if not self.connection:
    
    1446
    -            self.disconnect(on_purpose=True)
    
    1447
    -            app.nec.push_incoming_event(ConnectionLostEvent(None, conn=self,
    
    1448
    -                title=_('Could not connect to account %s') % self.name,
    
    1449
    -                msg=_('Connection with account %s has been lost. Retry '
    
    1450
    -                'connecting.') % self.name))
    
    1451
    -            return
    
    1452
    -        if app.config.get_per('accounts', self.name, 'anonymous_auth'):
    
    1453
    -            name = None
    
    1454
    -        else:
    
    1455
    -            name = app.config.get_per('accounts', self.name, 'name')
    
    1456
    -        self._register_handlers(self.connection, 'ssl')
    
    1457
    -        self.connection.auth(name, self.password, self.server_resource, 1,
    
    1458
    -                self.__on_auth)
    
    1423
    +        self.connection.auth(user=name,
    
    1424
    +                             password=self.password,
    
    1425
    +                             resource=self.server_resource,
    
    1426
    +                             sasl=True,
    
    1427
    +                             on_auth=self.__on_auth,
    
    1428
    +                             auth_mechs=auth_mechs)
    
    1459 1429
     
    
    1460 1430
         def _register_handlers(self, con, con_type):
    
    1461 1431
             self.peerhost = con.get_peerhost()
    

  • gajim/common/connection_handlers_events.py
    ... ... @@ -2188,10 +2188,6 @@ class SSLErrorEvent(nec.NetworkIncomingEvent):
    2188 2188
         name = 'ssl-error'
    
    2189 2189
         base_network_events = []
    
    2190 2190
     
    
    2191
    -class FingerprintErrorEvent(nec.NetworkIncomingEvent):
    
    2192
    -    name = 'fingerprint-error'
    
    2193
    -    base_network_events = []
    
    2194
    -
    
    2195 2191
     class UniqueRoomIdSupportedEvent(nec.NetworkIncomingEvent):
    
    2196 2192
         name = 'unique-room-id-supported'
    
    2197 2193
         base_network_events = []
    

  • gajim/dialogs.py
    ... ... @@ -5404,25 +5404,6 @@ SHA-256 Fingerprint: %(sha256)s
    5404 5404
             self.set_transient_for(parent)
    
    5405 5405
             self.set_title(_('Certificate for account %s') % account)
    
    5406 5406
     
    
    5407
    -
    
    5408
    -class CheckFingerprintDialog(YesNoDialog):
    
    5409
    -    def __init__(self, pritext='', sectext='', checktext='',
    
    5410
    -    on_response_yes=None, on_response_no=None, account=None, certificate=None):
    
    5411
    -        self.account = account
    
    5412
    -        self.cert = certificate
    
    5413
    -        YesNoDialog.__init__(self, pritext, sectext=sectext,
    
    5414
    -            checktext=checktext, on_response_yes=on_response_yes,
    
    5415
    -            on_response_no=on_response_no)
    
    5416
    -        self.set_title(_('SSL Certificate Verification for %s') % account)
    
    5417
    -        b = Gtk.Button(label=_('View cert…'))
    
    5418
    -        b.connect('clicked', self.on_cert_clicked)
    
    5419
    -        b.show_all()
    
    5420
    -        area = self.get_action_area()
    
    5421
    -        area.pack_start(b, True, True, 0)
    
    5422
    -
    
    5423
    -    def on_cert_clicked(self, button):
    
    5424
    -        CertificatDialog(self, self.account, self.cert)
    
    5425
    -
    
    5426 5407
     class SSLErrorDialog(ConfirmationDialogDoubleCheck):
    
    5427 5408
         def __init__(self, account, certificate, pritext, sectext, checktext1,
    
    5428 5409
         checktext2, on_response_ok=None, on_response_cancel=None):
    

  • gajim/gui_interface.py
    ... ... @@ -1354,29 +1354,24 @@ class Interface:
    1354 1354
                     certs = ''
    
    1355 1355
                     my_ca_certs = configpaths.get('MY_CACERTS')
    
    1356 1356
                     if os.path.isfile(my_ca_certs):
    
    1357
    -                    f = open(my_ca_certs)
    
    1358
    -                    certs = f.read()
    
    1359
    -                    f.close()
    
    1357
    +                    with open(my_ca_certs, encoding='utf-8') as f:
    
    1358
    +                        certs = f.read()
    
    1360 1359
                     if obj.cert in certs:
    
    1361 1360
                         dialogs.ErrorDialog(_('Certificate Already in File'),
    
    1362 1361
                             _('This certificate is already in file %s, so it\'s '
    
    1363 1362
                             'not added again.') % my_ca_certs)
    
    1364 1363
                     else:
    
    1365
    -                    f = open(my_ca_certs, 'a')
    
    1366
    -                    f.write(server + '\n')
    
    1367
    -                    f.write(obj.cert + '\n\n')
    
    1368
    -                    f.close()
    
    1369
    -            app.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
    
    1370
    -                obj.fingerprint_sha1)
    
    1371
    -            app.config.set_per('accounts', account, 'ssl_fingerprint_sha256',
    
    1372
    -                obj.fingerprint_sha256)
    
    1364
    +                    with open(my_ca_certs, 'a', encoding='utf-8') as f:
    
    1365
    +                        f.write(server + '\n')
    
    1366
    +                        f.write(obj.cert + '\n\n')
    
    1367
    +
    
    1373 1368
                 if is_checked[1]:
    
    1374 1369
                     ignore_ssl_errors = app.config.get_per('accounts', account,
    
    1375 1370
                         'ignore_ssl_errors').split()
    
    1376 1371
                     ignore_ssl_errors.append(str(obj.error_num))
    
    1377 1372
                     app.config.set_per('accounts', account, 'ignore_ssl_errors',
    
    1378 1373
                         ' '.join(ignore_ssl_errors))
    
    1379
    -            obj.conn.ssl_certificate_accepted()
    
    1374
    +            obj.conn.process_ssl_errors()
    
    1380 1375
     
    
    1381 1376
             def on_cancel():
    
    1382 1377
                 del self.instances[account]['online_dialog']['ssl_error']
    
    ... ... @@ -1412,46 +1407,6 @@ class Interface:
    1412 1407
                 'does not support anonymous connection' % server,
    
    1413 1408
                 transient_for=self.roster.window)
    
    1414 1409
     
    
    1415
    -    def handle_event_fingerprint_error(self, obj):
    
    1416
    -        # ('FINGERPRINT_ERROR', account, (new_fingerprint_sha1,new_fingerprint_sha256,))
    
    1417
    -        account = obj.conn.name
    
    1418
    -        def on_yes(is_checked):
    
    1419
    -            del self.instances[account]['online_dialog']['fingerprint_error']
    
    1420
    -            app.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
    
    1421
    -                obj.new_fingerprint_sha1)
    
    1422
    -            app.config.set_per('accounts', account, 'ssl_fingerprint_sha256',
    
    1423
    -                obj.new_fingerprint_sha256)
    
    1424
    -            # Reset the ignored ssl errors
    
    1425
    -            app.config.set_per('accounts', account, 'ignore_ssl_errors', '')
    
    1426
    -            obj.conn.ssl_certificate_accepted()
    
    1427
    -
    
    1428
    -        def on_no():
    
    1429
    -            del self.instances[account]['online_dialog']['fingerprint_error']
    
    1430
    -            obj.conn.disconnect(on_purpose=True)
    
    1431
    -            app.nec.push_incoming_event(OurShowEvent(None, conn=obj.conn,
    
    1432
    -                show='offline'))
    
    1433
    -
    
    1434
    -        pritext = _('SSL certificate error')
    
    1435
    -        sectext = _('It seems the SSL certificate of account %(account)s has '
    
    1436
    -            'changed and is not valid or your connection is being compromised.\n\n'
    
    1437
    -            'Old SHA-1 fingerprint: '
    
    1438
    -            '%(old_sha1)s\nOld SHA-256 fingerprint: %(old_sha256)s\n\n'
    
    1439
    -            'New SHA-1 fingerprint: %(new_sha1)s\nNew SHA-256 fingerprint: '
    
    1440
    -            '%(new_sha256)s\n\nDo you still want to connect '
    
    1441
    -            'and update the fingerprint of the certificate?') % \
    
    1442
    -            {'account': account,
    
    1443
    -            'old_sha1': app.config.get_per('accounts', account, 'ssl_fingerprint_sha1'),
    
    1444
    -            'old_sha256': app.config.get_per('accounts', account, 'ssl_fingerprint_sha256'),
    
    1445
    -            'new_sha1': obj.new_fingerprint_sha1,
    
    1446
    -            'new_sha256': obj.new_fingerprint_sha256}
    
    1447
    -        if 'fingerprint_error' in self.instances[account]['online_dialog']:
    
    1448
    -            self.instances[account]['online_dialog']['fingerprint_error'].\
    
    1449
    -                destroy()
    
    1450
    -        self.instances[account]['online_dialog']['fingerprint_error'] = \
    
    1451
    -            dialogs.CheckFingerprintDialog(pritext, sectext, on_response_yes=on_yes,
    
    1452
    -            on_response_no=on_no, account=obj.conn.name,
    
    1453
    -            certificate=obj.certificate)
    
    1454
    -
    
    1455 1410
         def handle_event_plain_connection(self, obj):
    
    1456 1411
             # ('PLAIN_CONNECTION', account, (connection))
    
    1457 1412
             def on_ok(is_checked):
    
    ... ... @@ -1578,7 +1533,6 @@ class Interface:
    1578 1533
                 'failed-decrypt': [(self.handle_event_failed_decrypt, ged.GUI2)],
    
    1579 1534
                 'file-request-error': [self.handle_event_file_request_error],
    
    1580 1535
                 'file-request-received': [self.handle_event_file_request],
    
    1581
    -            'fingerprint-error': [self.handle_event_fingerprint_error],
    
    1582 1536
                 'gc-invitation-received': [self.handle_event_gc_invitation],
    
    1583 1537
                 'gc-decline-received': [self.handle_event_gc_decline],
    
    1584 1538
                 'gc-presence-received': [self.handle_event_gc_presence],