diff options
-rw-r--r-- | src/leap/bitmask/backend.py | 11 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 15 | ||||
-rw-r--r-- | src/leap/bitmask/provider/__init__.py | 22 | ||||
-rw-r--r-- | src/leap/bitmask/provider/providerbootstrapper.py | 17 |
4 files changed, 64 insertions, 1 deletions
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 8a289a79..705a85be 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -194,6 +194,8 @@ class Signaler(QtCore.QObject): prov_problem_with_provider = QtCore.Signal(object) + prov_unsupported_client = QtCore.Signal(object) + # These will exist both in the backend and the front end. # The frontend might choose to not "interpret" all the signals # from the backend, but the backend needs to have all the signals @@ -205,6 +207,7 @@ class Signaler(QtCore.QObject): PROV_CHECK_CA_FINGERPRINT_KEY = "prov_check_ca_fingerprint" PROV_CHECK_API_CERTIFICATE_KEY = "prov_check_api_certificate" PROV_PROV_PROBLEM_WITH_PROVIER_KEY = "prov_problem_with_provider" + PROV_UNSUPPORTED_CLIENT = "prov_unsupported_client" def __init__(self): """ @@ -220,7 +223,8 @@ class Signaler(QtCore.QObject): self.PROV_DOWNLOAD_CA_CERT_KEY, self.PROV_CHECK_CA_FINGERPRINT_KEY, self.PROV_CHECK_API_CERTIFICATE_KEY, - self.PROV_PROV_PROBLEM_WITH_PROVIER_KEY + self.PROV_PROV_PROBLEM_WITH_PROVIER_KEY, + self.PROV_UNSUPPORTED_CLIENT ] for sig in signals: @@ -243,6 +247,11 @@ class Signaler(QtCore.QObject): # will do zmq.send_multipart, and the frontend version will be # similar to this log.msg("Signaling %s :: %s" % (key, data)) + + # for some reason emitting 'None' gives a segmentation fault. + if data is None: + data = '' + try: self._signals[key].emit(data) except KeyError: diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index f954006d..69cb4169 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -380,6 +380,9 @@ class MainWindow(QtGui.QMainWindow): partial(self._login_widget.set_status, self.tr("Unable to login: Problem with provider"))) + self._backend.signaler.prov_unsupported_client.connect( + self._needs_update) + def _backend_disconnect(self): """ Helper to disconnect from backend signals. @@ -856,6 +859,18 @@ class MainWindow(QtGui.QMainWindow): "<a href='https://leap.se'>More about LEAP" "</a>") % (VERSION, VERSION_HASH[:10], greet)) + def _needs_update(self): + """ + Display a warning dialog to inform the user that the app needs update. + """ + url = "https://dl.bitmask.net/" + msg = self.tr( + "The current client version is not supported " + "by this provider.<br>" + "Please update to latest version.<br><br>" + "You can get the latest version from {0}").format(url) + QtGui.QMessageBox.warning(self, self.tr("Update Needed"), msg) + def changeEvent(self, e): """ Reimplements the changeEvent method to minimize to tray diff --git a/src/leap/bitmask/provider/__init__.py b/src/leap/bitmask/provider/__init__.py index 53587d65..68f3ded0 100644 --- a/src/leap/bitmask/provider/__init__.py +++ b/src/leap/bitmask/provider/__init__.py @@ -18,6 +18,10 @@ Module initialization for leap.bitmask.provider """ import os + +from distutils.version import LooseVersion + +from leap.bitmask import __version__ as BITMASK_VERSION from leap.common.check import leap_assert @@ -32,3 +36,21 @@ def get_provider_path(domain): """ leap_assert(domain is not None, "get_provider_path: We need a domain") return os.path.join("leap", "providers", domain, "provider.json") + + +class SupportedClient(object): + """ + Class responsible of checking for client compatibility. + """ + + @classmethod + def supports(self, minimum_version): + """ + :param minimum_version: the version number of the client that + we need to check. + :type minimum_version: str + + :returns: True if that version is supported or False otherwise. + :return type: bool + """ + return LooseVersion(minimum_version) <= LooseVersion(BITMASK_VERSION) diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py index 947ba0c9..695b1593 100644 --- a/src/leap/bitmask/provider/providerbootstrapper.py +++ b/src/leap/bitmask/provider/providerbootstrapper.py @@ -30,6 +30,7 @@ from leap.bitmask import util from leap.bitmask.util.constants import REQUEST_TIMEOUT from leap.bitmask.services.abstractbootstrapper import AbstractBootstrapper from leap.bitmask.provider.supportedapis import SupportedAPIs +from leap.bitmask.provider import SupportedClient from leap.common import ca_bundle from leap.common.certs import get_digest from leap.common.files import check_and_fix_urw_only, get_mtime, mkdir_p @@ -45,6 +46,14 @@ class UnsupportedProviderAPI(Exception): pass +class UnsupportedClientVersionError(Exception): + """ + Raised when attempting to use a provider with an older + client than supported. + """ + pass + + class WrongFingerprint(Exception): """ Raised when a fingerprint comparison does not match. @@ -59,6 +68,8 @@ class ProviderBootstrapper(AbstractBootstrapper): If a check fails, the subsequent checks are not executed """ + MIN_CLIENT_VERSION = 'x-minimum-client-version' + def __init__(self, signaler=None, bypass_checks=False): """ Constructor for provider bootstrapper object @@ -187,6 +198,8 @@ class ProviderBootstrapper(AbstractBootstrapper): res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) + min_client_version = res.headers.get(self.MIN_CLIENT_VERSION, '0') + # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") @@ -194,6 +207,10 @@ class ProviderBootstrapper(AbstractBootstrapper): # end refactor, more or less... # XXX Watch out, have to check the supported api yet. else: + if not SupportedClient.supports(min_client_version): + self._signaler.signal(self._signaler.PROV_UNSUPPORTED_CLIENT) + raise UnsupportedClientVersionError() + provider_definition, mtime = get_content(res) provider_config = ProviderConfig() |