summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/provider
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2014-04-04 16:58:18 -0300
committerTomás Touceda <chiiph@leap.se>2014-04-04 16:58:18 -0300
commit81715dc47d77934c4f67d2527a56c28f58f0345d (patch)
tree6e66940af735e089803c5ce05ad1ce1df16c9d1e /src/leap/bitmask/provider
parent496036f15cf257d16b6594770812da64a249280c (diff)
parenteb4cdab9c6b8ff66bb4667cc6195d2c366122540 (diff)
Merge branch 'release-0.5.0'
Diffstat (limited to 'src/leap/bitmask/provider')
-rw-r--r--src/leap/bitmask/provider/__init__.py33
-rw-r--r--src/leap/bitmask/provider/providerbootstrapper.py103
-rw-r--r--src/leap/bitmask/provider/supportedapis.py38
-rw-r--r--src/leap/bitmask/provider/tests/test_providerbootstrapper.py11
4 files changed, 102 insertions, 83 deletions
diff --git a/src/leap/bitmask/provider/__init__.py b/src/leap/bitmask/provider/__init__.py
index 53587d65..89ff5d95 100644
--- a/src/leap/bitmask/provider/__init__.py
+++ b/src/leap/bitmask/provider/__init__.py
@@ -15,12 +15,20 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-Module initialization for leap.bitmask.provider
+Provider utilities.
"""
import os
+
+from pkg_resources import parse_version
+
+from leap.bitmask import __short_version__ as BITMASK_VERSION
from leap.common.check import leap_assert
+# The currently supported API versions by the client.
+SUPPORTED_APIS = ["1"]
+
+
def get_provider_path(domain):
"""
Returns relative path for provider config.
@@ -32,3 +40,26 @@ 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")
+
+
+def supports_api(api_version):
+ """
+ :param api_version: the version number of the api that we need to check
+ :type api_version: str
+
+ :returns: if that version is supported or not.
+ :return type: bool
+ """
+ return api_version in SUPPORTED_APIS
+
+
+def supports_client(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 parse_version(minimum_version) <= parse_version(BITMASK_VERSION)
diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py
index f5a2003f..2a519206 100644
--- a/src/leap/bitmask/provider/providerbootstrapper.py
+++ b/src/leap/bitmask/provider/providerbootstrapper.py
@@ -24,18 +24,18 @@ import sys
import requests
-from PySide import QtCore
-
-from leap.bitmask.config.providerconfig import ProviderConfig, MissingCACert
-from leap.bitmask.util.request_helpers import get_content
+from leap.bitmask import provider
from leap.bitmask import util
-from leap.bitmask.util.constants import REQUEST_TIMEOUT
+from leap.bitmask.config import flags
+from leap.bitmask.config.providerconfig import ProviderConfig, MissingCACert
+from leap.bitmask.provider import get_provider_path
from leap.bitmask.services.abstractbootstrapper import AbstractBootstrapper
-from leap.bitmask.provider.supportedapis import SupportedAPIs
+from leap.bitmask.util.constants import REQUEST_TIMEOUT
+from leap.bitmask.util.request_helpers import get_content
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
from leap.common.check import leap_assert, leap_assert_type, leap_check
+from leap.common.files import check_and_fix_urw_only, get_mtime, mkdir_p
logger = logging.getLogger(__name__)
@@ -47,6 +47,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.
@@ -61,25 +69,21 @@ class ProviderBootstrapper(AbstractBootstrapper):
If a check fails, the subsequent checks are not executed
"""
- # All dicts returned are of the form
- # {"passed": bool, "error": str}
- name_resolution = QtCore.Signal(dict)
- https_connection = QtCore.Signal(dict)
- download_provider_info = QtCore.Signal(dict)
+ MIN_CLIENT_VERSION = 'x-minimum-client-version'
- download_ca_cert = QtCore.Signal(dict)
- check_ca_fingerprint = QtCore.Signal(dict)
- check_api_certificate = QtCore.Signal(dict)
-
- def __init__(self, bypass_checks=False):
+ def __init__(self, signaler=None, bypass_checks=False):
"""
Constructor for provider bootstrapper object
+ :param signaler: Signaler object used to receive notifications
+ from the backend
+ :type signaler: Signaler
:param bypass_checks: Set to true if the app should bypass
- first round of checks for CA certificates at bootstrap
+ first round of checks for CA
+ certificates at bootstrap
:type bypass_checks: bool
"""
- AbstractBootstrapper.__init__(self, bypass_checks)
+ AbstractBootstrapper.__init__(self, signaler, bypass_checks)
self._domain = None
self._provider_config = None
@@ -95,9 +99,14 @@ class ProviderBootstrapper(AbstractBootstrapper):
:rtype: bool or str
"""
if self._bypass_checks:
- verify = False
+ return False
+
+ cert = flags.CA_CERT_FILE
+ if cert is not None:
+ verify = cert
else:
verify = ca_bundle.where()
+
return verify
def _check_name_resolution(self):
@@ -163,8 +172,8 @@ class ProviderBootstrapper(AbstractBootstrapper):
headers = {}
domain = self._domain.encode(sys.getfilesystemencoding())
provider_json = os.path.join(util.get_path_prefix(),
- "leap", "providers", domain,
- "provider.json")
+ get_provider_path(domain))
+
mtime = get_mtime(provider_json)
if self._download_if_needed and mtime:
@@ -195,6 +204,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")
@@ -202,6 +213,13 @@ class ProviderBootstrapper(AbstractBootstrapper):
# end refactor, more or less...
# XXX Watch out, have to check the supported api yet.
else:
+ if flags.APP_VERSION_CHECK:
+ # TODO split
+ if not provider.supports_client(min_client_version):
+ self._signaler.signal(
+ self._signaler.PROV_UNSUPPORTED_CLIENT)
+ raise UnsupportedClientVersionError()
+
provider_definition, mtime = get_content(res)
provider_config = ProviderConfig()
@@ -209,17 +227,20 @@ class ProviderBootstrapper(AbstractBootstrapper):
provider_config.save(["leap", "providers",
domain, "provider.json"])
- api_version = provider_config.get_api_version()
- if SupportedAPIs.supports(api_version):
- logger.debug("Provider definition has been modified")
- else:
- api_supported = ', '.join(SupportedAPIs.SUPPORTED_APIS)
- error = ('Unsupported provider API version. '
- 'Supported versions are: {0}. '
- 'Found: {1}.').format(api_supported, api_version)
-
- logger.error(error)
- raise UnsupportedProviderAPI(error)
+ if flags.API_VERSION_CHECK:
+ # TODO split
+ api_version = provider_config.get_api_version()
+ if provider.supports_api(api_version):
+ logger.debug("Provider definition has been modified")
+ else:
+ api_supported = ', '.join(provider.SUPPORTED_APIS)
+ error = ('Unsupported provider API version. '
+ 'Supported versions are: {0}. '
+ 'Found: {1}.').format(api_supported, api_version)
+
+ logger.error(error)
+ self._signaler.signal(self._signaler.PROV_UNSUPPORTED_API)
+ raise UnsupportedProviderAPI(error)
def run_provider_select_checks(self, domain, download_if_needed=False):
"""
@@ -238,9 +259,11 @@ class ProviderBootstrapper(AbstractBootstrapper):
self._download_if_needed = download_if_needed
cb_chain = [
- (self._check_name_resolution, self.name_resolution),
- (self._check_https, self.https_connection),
- (self._download_provider_info, self.download_provider_info)
+ (self._check_name_resolution,
+ self._signaler.PROV_NAME_RESOLUTION_KEY),
+ (self._check_https, self._signaler.PROV_HTTPS_CONNECTION_KEY),
+ (self._download_provider_info,
+ self._signaler.PROV_DOWNLOAD_PROVIDER_INFO_KEY)
]
return self.addCallbackChain(cb_chain)
@@ -367,9 +390,11 @@ class ProviderBootstrapper(AbstractBootstrapper):
self._download_if_needed = download_if_needed
cb_chain = [
- (self._download_ca_cert, self.download_ca_cert),
- (self._check_ca_fingerprint, self.check_ca_fingerprint),
- (self._check_api_certificate, self.check_api_certificate)
+ (self._download_ca_cert, self._signaler.PROV_DOWNLOAD_CA_CERT_KEY),
+ (self._check_ca_fingerprint,
+ self._signaler.PROV_CHECK_CA_FINGERPRINT_KEY),
+ (self._check_api_certificate,
+ self._signaler.PROV_CHECK_API_CERTIFICATE_KEY)
]
return self.addCallbackChain(cb_chain)
diff --git a/src/leap/bitmask/provider/supportedapis.py b/src/leap/bitmask/provider/supportedapis.py
deleted file mode 100644
index 3e650ba2..00000000
--- a/src/leap/bitmask/provider/supportedapis.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# supportedapis.py
-# Copyright (C) 2013 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-API Support check.
-"""
-
-
-class SupportedAPIs(object):
- """
- Class responsible of checking for API compatibility.
- """
- SUPPORTED_APIS = ["1"]
-
- @classmethod
- def supports(self, api_version):
- """
- :param api_version: the version number of the api that we need to check
- :type api_version: str
-
- :returns: if that version is supported or not.
- :return type: bool
- """
- return api_version in self.SUPPORTED_APIS
diff --git a/src/leap/bitmask/provider/tests/test_providerbootstrapper.py b/src/leap/bitmask/provider/tests/test_providerbootstrapper.py
index 88a4ff0b..6cf3e469 100644
--- a/src/leap/bitmask/provider/tests/test_providerbootstrapper.py
+++ b/src/leap/bitmask/provider/tests/test_providerbootstrapper.py
@@ -36,21 +36,22 @@ from nose.twistedtools import deferred, reactor
from twisted.internet import threads
from requests.models import Response
+from leap.bitmask import provider
+from leap.bitmask import util
+from leap.bitmask.backend import Signaler
from leap.bitmask.config.providerconfig import ProviderConfig
from leap.bitmask.crypto.tests import fake_provider
from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper
from leap.bitmask.provider.providerbootstrapper import UnsupportedProviderAPI
from leap.bitmask.provider.providerbootstrapper import WrongFingerprint
-from leap.bitmask.provider.supportedapis import SupportedAPIs
-from leap.bitmask import util
from leap.common.files import mkdir_p
-from leap.common.testing.https_server import where
from leap.common.testing.basetest import BaseLeapTest
+from leap.common.testing.https_server import where
class ProviderBootstrapperTest(BaseLeapTest):
def setUp(self):
- self.pb = ProviderBootstrapper()
+ self.pb = ProviderBootstrapper(Signaler())
def tearDown(self):
pass
@@ -488,7 +489,7 @@ class ProviderBootstrapperActiveTest(unittest.TestCase):
'leap.bitmask.config.providerconfig.ProviderConfig.get_ca_cert_path',
lambda x: where('cacert.pem'))
def test_download_provider_info_unsupported_api(self):
- self._setup_provider_config_with(SupportedAPIs.SUPPORTED_APIS[0],
+ self._setup_provider_config_with(provider.SUPPORTED_APIS[0],
tempfile.mkdtemp())
self._setup_providerbootstrapper(False)
self._produce_dummy_provider_json()