Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim-plugins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Hörist <forenjunkie@chello.at>2017-02-24 02:36:45 +0300
committerPhilipp Hörist <forenjunkie@chello.at>2017-02-25 17:12:53 +0300
commit14083c5b3020a325790b60b41cb65ce11a4ce9a6 (patch)
treec4a842406b56f66f6f8a6b5aead0cb52f6199cd7 /plugin_installer
parent95c04ebbcefdc4aaddf7405633df1fa4b6c0c73f (diff)
[plugin_installer] Add HTTPS Pinning
Diffstat (limited to 'plugin_installer')
-rw-r--r--plugin_installer/DST_Root_CA_X3.pem20
-rw-r--r--plugin_installer/plugin_installer.py83
2 files changed, 86 insertions, 17 deletions
diff --git a/plugin_installer/DST_Root_CA_X3.pem b/plugin_installer/DST_Root_CA_X3.pem
new file mode 100644
index 0000000..300cd7d
--- /dev/null
+++ b/plugin_installer/DST_Root_CA_X3.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/plugin_installer/plugin_installer.py b/plugin_installer/plugin_installer.py
index 6e9cfb1..4b37e3a 100644
--- a/plugin_installer/plugin_installer.py
+++ b/plugin_installer/plugin_installer.py
@@ -28,9 +28,11 @@ import io
import threading
import configparser
import os
+import ssl
import zipfile
import logging
import posixpath
+import urllib.error
from urllib.request import urlopen
from common import gajim
@@ -115,8 +117,7 @@ class PluginInstaller(GajimPlugin):
def check_update(self):
if hasattr(self, 'thread'):
return
- self.thread = DownloadAsync(self, check_update=True)
- self.thread.start()
+ self.start_download(check_update=True)
self.timeout_id = 0
@log_calls('PluginInstallerPlugin')
@@ -211,8 +212,7 @@ class PluginInstaller(GajimPlugin):
return
if not hasattr(self, 'thread'):
self.available_plugins_model.clear()
- self.thread = DownloadAsync(self, upgrading=True)
- self.thread.start()
+ self.start_download(upgrading=True)
def on_install_upgrade_clicked(self, widget):
self.install_button.set_property('sensitive', False)
@@ -221,17 +221,39 @@ class PluginInstaller(GajimPlugin):
if self.available_plugins_model[i][Column.UPGRADE]:
dir_list.append(self.available_plugins_model[i][Column.DIR])
- self.thread = DownloadAsync(self, remote_dirs=dir_list)
+ self.start_download(remote_dirs=dir_list)
+
+ def on_error(self, reason):
+ if reason == 'CERTIFICATE_VERIFY_FAILED':
+ YesNoDialog(
+ _('Security error during download'),
+ _('A security error occurred when '
+ 'downloading. The certificate of the '
+ 'plugin archive could not be verified. '
+ 'this might be a security attack. '
+ '\n\nYou can continue at your risk. '
+ 'Do you want to do so? '
+ '(not recommended)'
+ ),
+ on_response_yes=lambda dlg: self.start_download(
+ secure=False, upgrading=True))
+ else:
+ if self.available_plugins_model:
+ for i in range(len(self.available_plugins_model)):
+ self.available_plugins_model[i][Column.UPGRADE] = False
+ self.progressbar.hide()
+ text = GLib.markup_escape_text(reason)
+ WarningDialog(_('Error in download'),
+ _('An error occurred when downloading\n\n'
+ '<tt>[%s]</tt>' % (str(text))), self.window)
+
+ def start_download(self, secure=True, remote_dirs=None,
+ upgrading=False, check_update=False):
+ self.thread = DownloadAsync(
+ self, secure=secure, remote_dirs=remote_dirs,
+ upgrading=upgrading, check_update=check_update)
self.thread.start()
- def on_error(self, error_text):
- if self.available_plugins_model:
- for i in range(len(self.available_plugins_model)):
- self.available_plugins_model[i][Column.UPGRADE] = False
- self.progressbar.hide()
- text = GLib.markup_escape_text(error_text)
- WarningDialog(_('Error'), text, self.window)
-
def on_plugin_downloaded(self, plugin_dirs):
dialog = HigDialog(None, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
'', _('All selected plugins downloaded'))
@@ -329,7 +351,7 @@ class PluginInstaller(GajimPlugin):
class DownloadAsync(threading.Thread):
- def __init__(self, plugin, remote_dirs=None,
+ def __init__(self, plugin, secure=True, remote_dirs=None,
upgrading=False, check_update=False):
threading.Thread.__init__(self)
self.plugin = plugin
@@ -338,6 +360,7 @@ class DownloadAsync(threading.Thread):
self.model = plugin.available_plugins_model
self.remote_dirs = remote_dirs
self.upgrading = upgrading
+ self.secure = secure
self.check_update = check_update
icon = Gtk.Image()
self.def_icon = icon.render_icon(
@@ -357,9 +380,19 @@ class DownloadAsync(threading.Thread):
self.run_check_update()
else:
self.run_download_plugin_list()
- except Exception as e:
- GLib.idle_add(self.plugin.on_error, str(e))
+ except urllib.error.URLError as exc:
+ if isinstance(exc.reason, ssl.SSLError):
+ ssl_reason = exc.reason.reason
+ if ssl_reason == 'CERTIFICATE_VERIFY_FAILED':
+ log.exception('Certificate verify failed')
+ GLib.idle_add(self.plugin.on_error, ssl_reason)
+ except Exception as exc:
+ GLib.idle_add(self.plugin.on_error, str(exc))
log.exception('Error fetching plugin list')
+ finally:
+ if 'plugins' in gajim.interface.instances:
+ GLib.source_remove(self.pulse)
+ GLib.idle_add(self.progressbar.hide)
def parse_manifest(self, buf):
'''
@@ -380,7 +413,23 @@ class DownloadAsync(threading.Thread):
def download_url(self, url):
log.debug('Fetching {}'.format(url))
- request = urlopen(url)
+ ssl_args = {}
+ if self.secure:
+ ssl_args['context'] = ssl.create_default_context(
+ cafile=self.plugin.local_file_path('DST_Root_CA_X3.pem'))
+ else:
+ ssl_args['context'] = ssl.create_default_context()
+ ssl_args['context'].check_hostname = False
+ ssl_args['context'].verify_mode = ssl.CERT_NONE
+
+ for flag in ('OP_NO_SSLv2', 'OP_NO_SSLv3',
+ 'OP_NO_TLSv1', 'OP_NO_TLSv1_1',
+ 'OP_NO_COMPRESSION',
+ ):
+ log.info('Installer SSL: +%s' % flag)
+ ssl_args['context'].options |= getattr(ssl, flag)
+ request = urlopen(url, **ssl_args)
+
return io.BytesIO(request.read())
def run_check_update(self):