Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
c534d3a1
by Philipp Hörist at 2018-05-01T14:03:20+02:00
5 changed files:
- gajim/common/config.py
- gajim/common/connection.py
- gajim/common/connection_handlers_events.py
- gajim/dialogs.py
- gajim/gui_interface.py
Changes:
| ... | ... | @@ -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 ],
|
| ... | ... | @@ -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()
|
| ... | ... | @@ -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 = []
|
| ... | ... | @@ -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):
|
| ... | ... | @@ -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],
|