diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | MANIFEST.in | 2 | ||||
| -rw-r--r-- | README.txt | 5 | ||||
| -rw-r--r-- | data/TODO | 1 | ||||
| -rw-r--r-- | data/branding/cacert.pem | 24 | ||||
| -rw-r--r-- | pkg/branding/__init__.py | 15 | ||||
| -rw-r--r-- | pkg/branding/config.py | 11 | ||||
| -rw-r--r-- | pkg/requirements.pip | 2 | ||||
| -rwxr-xr-x | run_tests.sh | 2 | ||||
| -rwxr-xr-x | setup.py | 149 | ||||
| -rw-r--r-- | src/leap/__init__.py | 5 | ||||
| -rw-r--r-- | src/leap/base/config.py | 202 | ||||
| -rw-r--r-- | src/leap/base/constants.py | 15 | ||||
| -rw-r--r-- | src/leap/base/providers.py | 2 | ||||
| -rw-r--r-- | src/leap/base/tests/test_config.py | 64 | ||||
| -rw-r--r-- | src/leap/base/tests/test_providers.py | 6 | ||||
| -rw-r--r-- | src/leap/baseapp/eip.py | 21 | ||||
| -rw-r--r-- | src/leap/certs/__init__.py | 7 | ||||
| -rw-r--r-- | src/leap/eip/checks.py | 125 | ||||
| -rw-r--r-- | src/leap/eip/config.py | 66 | ||||
| -rw-r--r-- | src/leap/eip/constants.py | 2 | ||||
| -rw-r--r-- | src/leap/eip/eipconnection.py | 26 | ||||
| -rw-r--r-- | src/leap/eip/exceptions.py | 15 | ||||
| -rw-r--r-- | src/leap/eip/openvpnconnection.py | 7 | ||||
| -rw-r--r-- | src/leap/eip/specs.py | 10 | ||||
| -rw-r--r-- | src/leap/eip/tests/data.py | 14 | ||||
| -rw-r--r-- | src/leap/eip/tests/test_checks.py | 4 | ||||
| -rw-r--r-- | src/leap/eip/tests/test_config.py | 26 | 
28 files changed, 603 insertions, 227 deletions
| @@ -16,4 +16,6 @@ man/  share/  src/leap.egg-info/  src/leap_client.egg-info +src/leap/_branding.py +src/leap/certs/*.pem  MANIFEST diff --git a/MANIFEST.in b/MANIFEST.in index d67d3142..685cee16 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,5 @@  include pkg/* +include pkg/branding/*  include docs/*  include versioneer.py +include src/leap/certs/*.pem @@ -19,7 +19,7 @@ Dependencies  If you are on a debian-based system, you can run: -apt-get install python-qt4 python-qt4-doc pyqt4-dev-tools python-gnutls python-setuptools python-nose +apt-get install python-qt4 python-qt4-doc pyqt4-dev-tools python-gnutls libgnutls-dev python-setuptools python-nose  Install  --------------- @@ -87,7 +87,8 @@ Hack  (recommended)  virtualenv .  # ensure your .gitignore knows about it -bin/activate +source bin/activate +git checkout develop  pkg/postmkvenv.sh  python setup.py develop   diff --git a/data/TODO b/data/TODO deleted file mode 100644 index 580227ac..00000000 --- a/data/TODO +++ /dev/null @@ -1 +0,0 @@ -icons file and stuff should be moved here at some point! diff --git a/data/branding/cacert.pem b/data/branding/cacert.pem new file mode 100644 index 00000000..ed12e159 --- /dev/null +++ b/data/branding/cacert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIECzCCAl2gAwIBAgIEUFDp9TANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwRU +RVNUMB4XDTEyMDkxMjIwMDA1M1oXDTEzMDkxMjIwMDA1M1owDzENMAsGA1UEAxME +VEVTVDCCAbgwDQYJKoZIhvcNAQEBBQADggGlADCCAaACggGXANsoS1m9wj9iv+UV +BXfeq14SR94gSot96eJu7PZVRrcGlGe/PRfbmfxF3j/gXM9B8sIkyM2L46OMtOKw +1iOTKtYYdMhtnUSd3FRshWGtYeuy+OCe9umU0jfZDBZ2pXlUmSqCNqfD0OPkksYL +GDjQUKjaEd1oURwpCG8uEU+3tjBNCMuEwhcMEoUYmI8t4vss2hdFb+LKefVMPTzz +oiNM/o8Z/ANzWCC0qSW5FsB4wGhUS5HKLDOr4tACgdxaJSWtAqFFAnyMeG9g8aqe +PTM+URlqVnzzGckrJwBbd4y0zEpv/R7SAiSAP725cnB1GKptwdrcNIIHnQjOdAOl +uNg6JlRXrv6fV1gApka4INfJAf1yMf+fA0WdZ22UJQ9Up7tdzi8lL+3HsEpEx4Pz +NyzuqzEw9LJ6SUmMcE/VP00t4RjTOVoncwcLjvURY8jt2DQ9E36JEPwUoyALq/De +bGBjeK2KGzBZcOu1HZAwWLLWR2++WKuCEXbRbahwSIlbMfmAe8xGx4bbHol0D1A+ +wmu0uxjAze6FvUkCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8E +BQMDBwQAMB0GA1UdDgQWBBT/PX8XZ0Y2jDkppz6PHs23IgzQEDANBgkqhkiG9w0B +AQsFAAOCAZcAMfi+HLbcFaB0/Mv8/GkIdjpThUBVEeFrIiDy9GmGWUDOXgP1Skld +5H4eY5inE5lFfB69yacHIGS4OiZIBuBKfKNl5d6XO+ztJEJpG3yrbF4MtGV/aHEp +OlbJCncnk3fspBk6tFGrv4Inak4gza6SQPfBEZj29ciwfwrqrtuWZ7km+og0Clcd +pIB0g+DK0K//NtaDZDK0havQw2AFJKyXlNfI8XZ2jsNmQYR1wtiMci+UfGQr7bjn +Kw9yyVCf0ohXvnSK4ortz/bDQbcMWkK0m/VCCEK8PSldk+XFzPWFWn5ndKCczcvd +1BQc392n12ZstEuzm6+d9A0D3kCxralJUXUC+4kThq4Rtjey/gBjyZQnZ+5tIxMF +5ZFAStEglNxqm6HB17q7owJqTvIg9Cf9GATsvoFFQDJrBXewRX7cWVeSr0zNSQB4 +ydIlSUOkyE3AyfLN+lx8NVS/I7gp4fWDuHrh27NKKDtMxalxPL5pTGO7l4uTybLY +4aVzQYGvzA5HVS++VAtcTQ6TP9p4HURL2cllEU9u9A== +-----END CERTIFICATE----- diff --git a/pkg/branding/__init__.py b/pkg/branding/__init__.py new file mode 100644 index 00000000..0bd6befb --- /dev/null +++ b/pkg/branding/__init__.py @@ -0,0 +1,15 @@ +from .config import APP_BASE_NAME, APP_PREFIX, BRANDED_BUILD, BRANDED_OPTS + + +def get_name(): +    if BRANDED_BUILD is True: +        return APP_PREFIX + BRANDED_OPTS.get('short_name', 'name_unknown') +    else: +        return APP_BASE_NAME + + +def get_shortname(): +    if BRANDED_BUILD is True: +        return BRANDED_OPTS.get('short_name', 'name_unknown') + +__all__ = ['get_name'] diff --git a/pkg/branding/config.py b/pkg/branding/config.py new file mode 100644 index 00000000..665cfbda --- /dev/null +++ b/pkg/branding/config.py @@ -0,0 +1,11 @@ +# Configuration file for branding + +BRANDED_BUILD = True + +APP_BASE_NAME = "leap-client" +APP_PREFIX = "%s-" % APP_BASE_NAME + +BRANDED_OPTS = { +    'short_name': "springbok", +    'provider_domain': "springbok", +    'provider_ca_path': "data/branding/cacert.pem"} diff --git a/pkg/requirements.pip b/pkg/requirements.pip index 91257a07..5eeabf5c 100644 --- a/pkg/requirements.pip +++ b/pkg/requirements.pip @@ -3,4 +3,4 @@ configuration  requests  ping  netifaces -python-gnutls +python-gnutls==1.1.9  # see https://bugs.launchpad.net/ubuntu/+source/python-gnutls/+bug/1027129 diff --git a/run_tests.sh b/run_tests.sh index 96121d3e..6505dd54 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -77,7 +77,7 @@ function run_pep8 {    echo "Running pep8 ..."    srcfiles="src/leap tests"    # Just run PEP8 in current environment -  pep8_opts="--ignore=E202,W602 --exclude=*_rc.py --repeat" +  pep8_opts="--ignore=E202,W602 --exclude=*_rc.py,_version.py --repeat"    ${wrapper} pep8 ${pep8_opts} ${srcfiles}  } @@ -12,11 +12,17 @@ except ImportError:  import os  from pkg import utils +from pkg import branding  import versioneer  versioneer.versionfile_source = 'src/leap/_version.py'  versioneer.versionfile_build = 'leap/_version.py'  versioneer.tag_prefix = ''  # tags are like 1.2.0 -versioneer.parentdir_prefix = 'leap_client-' +#versioneer.parentdir_prefix = 'leap_client-' +versioneer.parentdir_prefix = branding.APP_PREFIX + +branding.brandingfile = 'src/leap/_branding.py' +branding.brandingfile_build = 'leap/_branding.py' +branding.cert_path = 'src/leap/certs'  setup_root = os.path.dirname(__file__)  sys.path.insert(0, os.path.join(setup_root, "src")) @@ -37,11 +43,139 @@ trove_classifiers = [      "Topic :: Utilities"  ] +BRANDING_OPTS = """ +# Do NOT manually edit this file! +# This file has been written from pkg/branding/config.py data by leap setup.py +# script. + +BRANDING = { +    'short_name': "%(short_name)s", +    'provider_domain': "%(provider_domain)s", +    'provider_ca_file': "%(provider_ca_file)s"} +""" + + +def write_to_branding_file(filename, branding_dict): +    f = open(filename, "w") +    f.write(BRANDING_OPTS % branding_dict) +    f.close() + + +def copy_pemfile_to_certdir(frompath, topath): +    with open(frompath, "r") as cert_f: +        cert_s = cert_f.read() +    with open(topath, "w") as f: +        f.write(cert_s) + + +def do_branding(targetfile=branding.brandingfile): +    if branding.BRANDED_BUILD: +        opts = branding.BRANDED_OPTS +        print("DOING BRANDING FOR LEAP") +        certpath = opts['provider_ca_path'] +        shortname = opts['short_name'] +        tocertfile = shortname + '-cacert.pem' +        topath = os.path.join( +            branding.cert_path, +            tocertfile) +        copy_pemfile_to_certdir( +            certpath, +            topath) +        opts['provider_ca_file'] = tocertfile +        write_to_branding_file( +            targetfile, +            opts) +    else: +        print('not running branding because BRANDED_BUILD set to False') + + +from setuptools import Command + + +class DoBranding(Command): +    description = "copy the branding info the the top level package" +    user_options = [] + +    def initialize_options(self): +        pass + +    def finalize_options(self): +        pass + +    def run(self): +        do_branding() + +from distutils.command.build import build as _build +from distutils.command.sdist import sdist as _sdist + + +class cmd_build(_build): +    def run(self): +        #versioneer.cmd_build(self) +        _build.run(self) + +        # versioneer +        versions = versioneer.get_versions(verbose=True) +        # now locate _version.py in the new build/ directory and replace it +        # with an updated value +        target_versionfile = os.path.join( +            self.build_lib, +            versioneer.versionfile_build) +        print("UPDATING %s" % target_versionfile) +        os.unlink(target_versionfile) +        f = open(target_versionfile, "w") +        f.write(versioneer.SHORT_VERSION_PY % versions) +        f.close() + +        # branding +        target_brandingfile = os.path.join( +            self.build_lib, +            branding.brandingfile_build) +        do_branding(targetfile=target_brandingfile) + + +class cmd_sdist(_sdist): +    def run(self): +        # versioneer: +        versions = versioneer.get_versions(verbose=True) +        self._versioneer_generated_versions = versions +        # unless we update this, the command will keep using the old version +        self.distribution.metadata.version = versions["version"] + +        # branding: +        do_branding() +        return _sdist.run(self) + +    def make_release_tree(self, base_dir, files): +        _sdist.make_release_tree(self, base_dir, files) +        # now locate _version.py in the new base_dir directory (remembering +        # that it may be a hardlink) and replace it with an updated value +        target_versionfile = os.path.join( +            base_dir, versioneer.versionfile_source) +        print("UPDATING %s" % target_versionfile) +        os.unlink(target_versionfile) +        f = open(target_versionfile, "w") +        f.write( +            versioneer.SHORT_VERSION_PY % self._versioneer_generated_versions) +        f.close() + + +cmdclass = versioneer.get_cmdclass() +cmdclass["branding"] = DoBranding +cmdclass["build"] = cmd_build +cmdclass["sdist"] = cmd_sdist + +launcher_name = branding.get_shortname() +if launcher_name: +    leap_launcher = 'leap-%s-client=leap.app:main' % launcher_name +else: +    leap_launcher = 'leap=leap.app:main' +  setup( -    name='leap-client', +    name=branding.get_name(),      package_dir={"": "src"},      version=versioneer.get_version(), -    cmdclass=versioneer.get_cmdclass(), +    cmdclass=cmdclass,      description="the internet encryption toolkit",      long_description=(          "Desktop Client for the LEAP Platform." @@ -79,8 +213,11 @@ setup(              ["pkg/linux/polkit/net.openvpn.gui.leap.policy"])      ],      platforms="all", -    scripts=["pkg/scripts/leap"], -    entry_points=""" +    #scripts=["pkg/scripts/leap"], +    entry_points = { +        'console_scripts': [leap_launcher] +    }, +    #entry_points="""      # -*- Entry points: -*- -    """, +    #""",  ) diff --git a/src/leap/__init__.py b/src/leap/__init__.py index 75bddd6d..5e003931 100644 --- a/src/leap/__init__.py +++ b/src/leap/__init__.py @@ -28,3 +28,8 @@ except ImportError:      pass  __full_version__ = __appname__ + '/' + str(__version__) + +try: +    from leap._branding import BRANDING as __branding +except ImportError: +    __branding = {} diff --git a/src/leap/base/config.py b/src/leap/base/config.py index 5a52637c..a468a849 100644 --- a/src/leap/base/config.py +++ b/src/leap/base/config.py @@ -18,6 +18,9 @@ from leap.base import exceptions  from leap.base import constants  from leap.util.fileutil import (mkdir_p) +# move to base! +from leap.eip import exceptions as eipexceptions +  class BaseLeapConfig(object):      slug = None @@ -145,9 +148,9 @@ class JSONLeapConfig(BaseLeapConfig):                  config[k] = v()          self._config.serialize(to) -    def load(self, fromfile=None, from_uri=None, fetcher=None): +    def load(self, fromfile=None, from_uri=None, fetcher=None, verify=False):          if from_uri is not None: -            fetched = self.fetch(from_uri, fetcher=fetcher) +            fetched = self.fetch(from_uri, fetcher=fetcher, verify=verify)              if fetched:                  return          if fromfile is None: @@ -156,12 +159,21 @@ class JSONLeapConfig(BaseLeapConfig):          # XXX check for no errors, etc          self._config.config = newconfig -    def fetch(self, uri, fetcher=None): +    def fetch(self, uri, fetcher=None, verify=True):          if not fetcher:              fetcher = self.fetcher -        request = fetcher.get(uri) +        logger.debug('verify: %s', verify) +        request = fetcher.get(uri, verify=verify) + +        # XXX get 404, ... +        # and raise a UnableToFetch...          request.raise_for_status()          fd, fname = tempfile.mkstemp(suffix=".json") +        if not request.json: +            try: +                json.loads(request.content) +            except ValueError: +                raise eipexceptions.LeapBadConfigFetchedError          with open(fname, 'w') as tmp:              tmp.write(json.dumps(request.json))          self._loadtemp(fname) @@ -239,7 +251,7 @@ def get_config_file(filename, folder=None):  def get_default_provider_path():      default_subpath = os.path.join("providers", -                                   constants.DEFAULT_TEST_PROVIDER) +                                   constants.DEFAULT_PROVIDER)      default_provider_path = get_config_file(          '',          folder=default_subpath) @@ -266,55 +278,55 @@ def get_groupname():  # json stuff  # XXX merge with JSONConfig / EIPChecks as appropiate. -def get_config_json(config_file=None): -    """ -    will replace get_config function be developing them -    in parralel for branch purposes. -    @param: configuration file -    @type: file -    @rparam: configuration turples -    @rtype: dictionary -    """ -    if not config_file: +#def get_config_json(config_file=None): +    #""" +    #will replace get_config function be developing them +    #in parralel for branch purposes. +    #@param: configuration file +    #@type: file +    #@rparam: configuration turples +    #@rtype: dictionary +    #""" +    #if not config_file:          #TODO: NOT SURE WHAT this default should be, if anything -        fpath = get_config_file('eip.json') -        if not os.path.isfile(fpath): -            dpath, cfile = os.path.split(fpath) -            if not os.path.isdir(dpath): -                mkdir_p(dpath) -            with open(fpath, 'wb') as configfile: -                configfile.flush() -        try: -            return json.load(open(fpath)) -        except ValueError: -            raise exceptions.MissingConfigFileError - -    else: +        #fpath = get_config_file('eip.json') +        #if not os.path.isfile(fpath): +            #dpath, cfile = os.path.split(fpath) +            #if not os.path.isdir(dpath): +                #mkdir_p(dpath) +            #with open(fpath, 'wb') as configfile: +                #configfile.flush() +        #try: +            #return json.load(open(fpath)) +        #except ValueError: +            #raise exceptions.MissingConfigFileError +# +    #else:          #TODO: add validity checks of file -        try: -            return json.load(open(config_file)) -        except IOError: -            raise exceptions.MissingConfigFileError - - -def get_definition_file(url=None): -    """ -    """ +        #try: +            #return json.load(open(config_file)) +        #except IOError: +            #raise exceptions.MissingConfigFileError +# +# +#def get_definition_file(url=None): +    #""" +    #"""      #TODO: determine good default location of definition file. -    r = requests.get(url) -    return r.json - - -def is_internet_up(): -    """TODO: Build more robust network diagnosis capabilities -    """ -    try: -        requests.get('http://128.30.52.45', timeout=1) -        return True -    except requests.Timeout:  # as err: -        pass -    return False - +    #r = requests.get(url) +    #return r.json +# +# +#def is_internet_up(): +    #"""TODO: Build more robust network diagnosis capabilities +    #""" +    #try: +        #requests.get('http://128.30.52.45', timeout=1) +        #return True +    #except requests.Timeout:  # as err: +        #pass +    #return False +#  # XXX DEPRECATE.  # move to eip.checks  # @@ -323,49 +335,49 @@ def is_internet_up():  # moving it here transiently until I clean merge commit.  # -- kali 2012-08-24 00:32  # - - -class Configuration(object): -    """ -    All configurations (providers et al) will be managed in this class. -    """ -    def __init__(self, provider_url=None): -        try: +# +# +#class Configuration(object): +    #""" +    #All configurations (providers et al) will be managed in this class. +    #""" +    #def __init__(self, provider_url=None): +        #try:              #requests.get('foo') -            self.providers = {} -            self.error = False -            provider_file = self.check_and_get_definition_file(provider_url) -            self.providers['default'] = get_config_json(provider_file) -        except (requests.HTTPError, requests.RequestException) as e: -            self.error = e.message -        except requests.ConnectionError as e: -            if e.message == "[Errno 113] No route to host": -                if not is_internet_up: +            #self.providers = {} +            #self.error = False +            #provider_file = self.check_and_get_definition_file(provider_url) +            #self.providers['default'] = get_config_json(provider_file) +        #except (requests.HTTPError, requests.RequestException) as e: +            #self.error = e.message +        #except requests.ConnectionError as e: +            #if e.message == "[Errno 113] No route to host": +                #if not is_internet_up:                      # this was meant to be a function invocation I guess... -                    self.error = "No valid internet connection found" -                else: -                    self.error = "Provider server appears currently down." - -    def check_and_get_definition_file(self, provider_url): -        """ -        checks if provider definition.json file is present. -        if not downloads one from the web. -        """ -        default_provider_path = get_default_provider_path() - -        if not os.path.isdir(default_provider_path): -            mkdir_p(default_provider_path) - -        definition_file = get_config_file( -            'definition.json', -            folder=default_provider_path) - -        if os.path.isfile(definition_file): -            return - -        else: -            r = requests.get(provider_url) -            r.raise_for_status() -            with open(definition_file, 'wb') as f: -                f.write(json.dumps(r.json, indent=4)) -            return definition_file +                    #self.error = "No valid internet connection found" +                #else: +                    #self.error = "Provider server appears currently down." +# +    #def check_and_get_definition_file(self, provider_url): +        #""" +        #checks if provider definition.json file is present. +        #if not downloads one from the web. +        #""" +        #default_provider_path = get_default_provider_path() +# +        #if not os.path.isdir(default_provider_path): +            #mkdir_p(default_provider_path) +# +        #definition_file = get_config_file( +            #'definition.json', +            #folder=default_provider_path) +# +        #if os.path.isfile(definition_file): +            #return +# +        #else: +            #r = requests.get(provider_url) +            #r.raise_for_status() +            #with open(definition_file, 'wb') as f: +                #f.write(json.dumps(r.json, indent=4)) +            #return definition_file diff --git a/src/leap/base/constants.py b/src/leap/base/constants.py index 6266c693..7a1415fb 100644 --- a/src/leap/base/constants.py +++ b/src/leap/base/constants.py @@ -1,23 +1,26 @@  """constants to be used in base module""" -APP_NAME = "leap" +from leap import __branding +APP_NAME = __branding.get("short_name", "leap")  # default provider placeholder  # using `example.org` we make sure that this  # is not going to be resolved during the tests phases  # (we expect testers to add it to their /etc/hosts -DEFAULT_TEST_PROVIDER = "testprovider.example.org" +DEFAULT_PROVIDER = __branding.get( +    "provider_domain", +    "testprovider.example.org") -DEFINITION_EXPECTED_PATH = "provider-definition.json" +DEFINITION_EXPECTED_PATH = "provider.json"  DEFAULT_PROVIDER_DEFINITION = { -    u'api_uri': u'https://api.testprovider.example.org/', +    u'api_uri': u'https://api.%s/' % DEFAULT_PROVIDER,      u'api_version': u'0.1.0',      u'ca_cert': u'8aab80ae4326fd30721689db813733783fe0bd7e', -    u'ca_cert_uri': u'https://testprovider.example.org/cacert.pem', +    u'ca_cert_uri': u'https://%s/cacert.pem' % DEFAULT_PROVIDER,      u'description': {u'en': u'This is a test provider'},      u'display_name': {u'en': u'Test Provider'}, -    u'domain': u'testprovider.example.org', +    u'domain': u'%s' % DEFAULT_PROVIDER,      u'enrollment_policy': u'open',      u'public_key': u'cb7dbd679f911e85bc2e51bd44afd7308ee19c21',      u'serial': 1, diff --git a/src/leap/base/providers.py b/src/leap/base/providers.py index ce30d4a4..7b219cc7 100644 --- a/src/leap/base/providers.py +++ b/src/leap/base/providers.py @@ -9,7 +9,7 @@ class LeapProviderDefinition(baseconfig.JSONLeapConfig):      def _get_slug(self):          provider_path = baseconfig.get_default_provider_path()          return baseconfig.get_config_file( -            'provider-definition.json', +            'provider.json',              folder=provider_path)      def _set_slug(self, *args, **kwargs): diff --git a/src/leap/base/tests/test_config.py b/src/leap/base/tests/test_config.py index 40461b99..bede5ea1 100644 --- a/src/leap/base/tests/test_config.py +++ b/src/leap/base/tests/test_config.py @@ -65,15 +65,15 @@ class ProviderTest(BaseLeapTest):          pass -class BareHomeTestCase(ProviderTest): +# XXX depreacated. similar test in eip.checks -    __name__ = "provider_config_tests_bare_home" - -    # XXX review. is it still needed? - -    def test_should_raise_if_missing_eip_json(self): -        with self.assertRaises(exceptions.MissingConfigFileError): -            config.get_config_json(os.path.join(self.home, 'eip.json')) +#class BareHomeTestCase(ProviderTest): +# +    #__name__ = "provider_config_tests_bare_home" +# +    #def test_should_raise_if_missing_eip_json(self): +        #with self.assertRaises(exceptions.MissingConfigFileError): +            #config.get_config_json(os.path.join(self.home, 'eip.json'))  class ProviderDefinitionTestCase(ProviderTest): @@ -94,8 +94,10 @@ class ProviderDefinitionTestCase(ProviderTest):              json.dump(eipconstants.EIP_SAMPLE_JSON, fp) -# these tests below should move to wherever -# we put the fetcher for provider files and related stuff. +# these tests below should move to +# eip.checks +# config.Configuration has been deprecated +  # TODO:  # - We're instantiating a ProviderTest because we're doing the home wipeoff  # on setUpClass instead of the setUp (for speedup of the general cases). @@ -112,26 +114,26 @@ class ProviderDefinitionTestCase(ProviderTest):  # (so we can pass mock easily). -class ProviderFetchConError(ProviderTest): -    def test_connection_error(self): -        with mock.patch.object(requests, "get") as mock_method: -            mock_method.side_effect = requests.ConnectionError -            cf = config.Configuration() -            self.assertIsInstance(cf.error, str) - - -class ProviderFetchHttpError(ProviderTest): -    def test_file_not_found(self): -        with mock.patch.object(requests, "get") as mock_method: -            mock_method.side_effect = requests.HTTPError -            cf = config.Configuration() -            self.assertIsInstance(cf.error, str) - - -class ProviderFetchInvalidUrl(ProviderTest): -    def test_invalid_url(self): -        cf = config.Configuration("ht") -        self.assertTrue(cf.error) +#class ProviderFetchConError(ProviderTest): +    #def test_connection_error(self): +        #with mock.patch.object(requests, "get") as mock_method: +            #mock_method.side_effect = requests.ConnectionError +            #cf = config.Configuration() +            #self.assertIsInstance(cf.error, str) +# +# +#class ProviderFetchHttpError(ProviderTest): +    #def test_file_not_found(self): +        #with mock.patch.object(requests, "get") as mock_method: +            #mock_method.side_effect = requests.HTTPError +            #cf = config.Configuration() +            #self.assertIsInstance(cf.error, str) +# +# +#class ProviderFetchInvalidUrl(ProviderTest): +    #def test_invalid_url(self): +        #cf = config.Configuration("ht") +        #self.assertTrue(cf.error)  # end provider fetch tests @@ -218,7 +220,7 @@ class ConfigHelperFunctions(BaseLeapTest):              config.get_default_provider_path(),              os.path.expanduser(                  '~/.config/leap/providers/%s/' % -                constants.DEFAULT_TEST_PROVIDER) +                constants.DEFAULT_PROVIDER)          )      # validate ip diff --git a/src/leap/base/tests/test_providers.py b/src/leap/base/tests/test_providers.py index 23f63a95..9e0ff90c 100644 --- a/src/leap/base/tests/test_providers.py +++ b/src/leap/base/tests/test_providers.py @@ -6,9 +6,11 @@ except ImportError:  import os +from leap import __branding as BRANDING  from leap.testing.basetest import BaseLeapTest  from leap.base import providers +  EXPECTED_DEFAULT_CONFIG = {      "api_version": "0.1.0",      "description": "test provider", @@ -45,8 +47,8 @@ class TestLeapProviderDefinition(BaseLeapTest):              os.path.join(                  self.home,                  '.config', 'leap', 'providers', -                'testprovider.example.org', -                'provider-definition.json')) +                '%s' % BRANDING.get('provider_domain'), +                'provider.json'))          with self.assertRaises(AttributeError):              self.definition.slug = 23 diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py index 68bd2f24..6c147cb4 100644 --- a/src/leap/baseapp/eip.py +++ b/src/leap/baseapp/eip.py @@ -1,5 +1,7 @@ +from __future__ import print_function  import logging  import time +import sys  from PyQt4 import QtCore @@ -38,8 +40,9 @@ class EIPConductorAppMixin(object):              debug=self.debugmode,              ovpn_verbosity=opts.openvpn_verb) -        # XXX remove skip download when sample service is ready -        self.conductor.run_checks(skip_download=True) +        # XXX get skip_download from cli flag +        skip_download = False +        self.conductor.run_checks(skip_download=skip_download)          self.error_check()          # XXX should receive "ready" signal @@ -58,13 +61,11 @@ class EIPConductorAppMixin(object):          """          logger.debug('error check') -        ##################################### -        # XXX refactor in progress (by #504) -          errq = self.conductor.error_queue          while errq.qsize() != 0:              logger.debug('%s errors left in conductor queue', errq.qsize()) -            error = errq.get() +            # we get exception and original traceback from queue +            error, tb = errq.get()              # redundant log, debugging the loop.              logger.error('%s: %s', error.__class__.__name__, error.message) @@ -73,10 +74,8 @@ class EIPConductorAppMixin(object):                  self.handle_eip_error(error)              else: -                # This is not quite working. FIXME -                import traceback -                traceback.print_exc() -                raise error +                # deprecated form of raising exception. +                raise error, None, tb              if error.failfirst is True:                  break @@ -132,6 +131,8 @@ class EIPConductorAppMixin(object):              ErrorDialog(errtype="critical",                          msg=message,                          label="critical error") +        elif error.warning: +            logger.warning(error.message)          else:              dialog = ErrorDialog() diff --git a/src/leap/certs/__init__.py b/src/leap/certs/__init__.py new file mode 100644 index 00000000..c4d009b1 --- /dev/null +++ b/src/leap/certs/__init__.py @@ -0,0 +1,7 @@ +import os + +_where = os.path.split(__file__)[0] + + +def where(filename): +    return os.path.join(_where, filename) diff --git a/src/leap/eip/checks.py b/src/leap/eip/checks.py index f368c551..cf758314 100644 --- a/src/leap/eip/checks.py +++ b/src/leap/eip/checks.py @@ -9,6 +9,8 @@ import netifaces  import ping  import requests +from leap import __branding as BRANDING +from leap import certs  from leap.base import constants as baseconstants  from leap.base import providers  from leap.eip import config as eipconfig @@ -20,6 +22,11 @@ from leap.util.fileutil import mkdir_p  logger = logging.getLogger(name=__name__)  """ +ProviderCertChecker +------------------- +Checks on certificates. To be moved to base. +docs TBD +  EIPConfigChecker  ----------  It is used from the eip conductor (a instance of EIPConnection that is @@ -36,14 +43,15 @@ LeapNetworkChecker  ------------------  Network checks. To be moved to base.  docs TBD - -ProviderCertChecker -------------------- -Checks on certificates. -docs TBD  """ +def get_ca_cert(): +    ca_file = BRANDING.get('provider_ca_file') +    if ca_file: +        return certs.where(ca_file) + +  class LeapNetworkChecker(object):      """      all network related checks @@ -67,6 +75,7 @@ class LeapNetworkChecker(object):          # XXX we probably should raise an exception here?          # unless we use this as smoke test          try: +            # XXX remove this hardcoded random ip              requests.get('http://216.172.161.165')          except (requests.HTTPError, requests.RequestException) as e:              self.error = e.message @@ -124,7 +133,7 @@ class ProviderCertChecker(object):      """      def __init__(self, fetcher=requests):          self.fetcher = fetcher -        self.cacert = None +        self.cacert = get_ca_cert()      def run_all(self, checker=None, skip_download=False):          if not checker: @@ -138,9 +147,10 @@ class ProviderCertChecker(object):          # For MVS          checker.is_there_provider_ca() -        checker.is_https_working() -        checker.check_new_cert_needed() -        #checker.download_new_client_cert() + +        # XXX FAKE IT!!! +        checker.is_https_working(verify=False) +        checker.check_new_cert_needed(verify=False)      def download_ca_cert(self):          # MVS+ @@ -159,34 +169,49 @@ class ProviderCertChecker(object):          raise NotImplementedError      def is_there_provider_ca(self): -        # XXX fake it till you make it! :P +        from leap import certs +        logger.debug('do we have provider_ca?') +        cacert_path = BRANDING.get('provider_ca_file', None) +        if not cacert_path: +            logger.debug('False') +            return False +        self.cacert = certs.where(cacert_path) +        logger.debug('True')          return True -        # enable this when we have -        # a custom "branded" bundle -        # certs package. -        try: -            from leap.custom import certs -        except ImportError: -            raise -        self.cacert = certs.where('cacert.pem') -      def is_https_working(self, uri=None, verify=True): +        if uri is None: +            uri = self._get_root_uri()          # XXX raise InsecureURI or something better +        logger.debug('is https working?') +        logger.debug('uri: %s', uri)          assert uri.startswith('https')          if verify is True and self.cacert is not None: +            logger.debug('verify cert: %s', self.cacert)              verify = self.cacert -        self.fetcher.get(uri, verify=verify) -        return True +        try: +            self.fetcher.get(uri, verify=verify) +        except requests.exceptions.SSLError: +            logger.debug('False!') +            raise eipexceptions.EIPBadCertError +        else: +            logger.debug('True') +            return True -    def check_new_cert_needed(self, skip_download=False): +    def check_new_cert_needed(self, skip_download=False, verify=True): +        logger.debug('is new cert needed?')          if not self.is_cert_valid(do_raise=False): -            self.download_new_client_cert(skip_download=skip_download) +            logger.debug('True') +            self.download_new_client_cert( +                skip_download=skip_download, +                verify=verify)              return True +        logger.debug('False')          return False      def download_new_client_cert(self, uri=None, verify=True,                                   skip_download=False): +        logger.debug('download new client cert')          if skip_download:              return True          if uri is None: @@ -195,20 +220,28 @@ class ProviderCertChecker(object):          assert uri.startswith('https')          if verify is True and self.cacert is not None:              verify = self.cacert -        req = self.fetcher.get(uri, verify=verify) -        pemfile_content = req.content -        self.is_valid_pemfile(pemfile_content) -        cert_path = self._get_client_cert_path() -        self.write_cert(pemfile_content, to=cert_path) +        try: +            req = self.fetcher.get(uri, verify=verify) +            req.raise_for_status() +        except requests.exceptions.SSLError: +            logger.warning('SSLError while fetching cert. ' +                           'Look below for stack trace.') +            # XXX raise better exception +            raise +        try: +            pemfile_content = req.content +            self.is_valid_pemfile(pemfile_content) +            cert_path = self._get_client_cert_path() +            self.write_cert(pemfile_content, to=cert_path) +        except: +            logger.warning('Error while validating cert') +            raise          return True      def is_cert_valid(self, cert_path=None, do_raise=True):          exists = lambda: self.is_certificate_exists()          valid_pemfile = lambda: self.is_valid_pemfile()          not_expired = lambda: self.is_cert_not_expired() -        #print 'exists?', exists -        #print 'valid', valid_pemfile -        #print 'not expired', not_expired          valid = exists() and valid_pemfile() and not_expired()          if not valid: @@ -250,18 +283,26 @@ class ProviderCertChecker(object):              # XXX use gnutls for get proper              # validation.              # crypto.X509Certificate(cert_s) +            sep = "-" * 5 + "BEGIN CERTIFICATE" + "-" * 5 +            # we might have private key and cert in the same file +            certparts = cert_s.split(sep) +            if len(certparts) > 1: +                cert_s = sep + certparts[1]              ssl.PEM_cert_to_DER_cert(cert_s)          except:              # XXX raise proper exception              raise          return True +    def _get_root_uri(self): +        return u"https://%s/" % baseconstants.DEFAULT_PROVIDER +      def _get_client_cert_uri(self): -        return "https://%s/cert/get" % (baseconstants.DEFAULT_TEST_PROVIDER) +        # XXX get the whole thing from constants +        return "https://%s/1/cert" % (baseconstants.DEFAULT_PROVIDER)      def _get_client_cert_path(self):          # MVS+ : get provider path -        #import ipdb;ipdb.set_trace()          return eipspecs.client_cert_path()      def write_cert(self, pemfile_content, to=None): @@ -370,7 +411,11 @@ class EIPConfigChecker(object):              domain = config.get('provider', None)              uri = self._get_provider_definition_uri(domain=domain) -        self.defaultprovider.load(from_uri=uri, fetcher=self.fetcher) +        # FIXME! Pass ca path verify!!! +        self.defaultprovider.load( +            from_uri=uri, +            fetcher=self.fetcher, +            verify=False)          self.defaultprovider.save()      def fetch_eip_service_config(self, skip_download=False, @@ -414,14 +459,18 @@ class EIPConfigChecker(object):      def _get_provider_definition_uri(self, domain=None, path=None):          if domain is None: -            domain = baseconstants.DEFAULT_TEST_PROVIDER +            domain = baseconstants.DEFAULT_PROVIDER          if path is None:              path = baseconstants.DEFINITION_EXPECTED_PATH -        return "https://%s/%s" % (domain, path) +        uri = u"https://%s/%s" % (domain, path) +        logger.debug('getting provider definition from %s' % uri) +        return uri      def _get_eip_service_uri(self, domain=None, path=None):          if domain is None: -            domain = baseconstants.DEFAULT_TEST_PROVIDER +            domain = baseconstants.DEFAULT_PROVIDER          if path is None:              path = eipconstants.EIP_SERVICE_EXPECTED_PATH -        return "https://%s/%s" % (domain, path) +        uri = "https://%s/%s" % (domain, path) +        logger.debug('getting eip service file from %s', uri) +        return uri diff --git a/src/leap/eip/config.py b/src/leap/eip/config.py index c0e17a19..44922310 100644 --- a/src/leap/eip/config.py +++ b/src/leap/eip/config.py @@ -3,7 +3,9 @@ import os  import platform  import tempfile -from leap.util.fileutil import (which, check_and_fix_urw_only) +from leap import __branding as BRANDING +from leap import certs +from leap.util.fileutil import (which, mkdir_p, check_and_fix_urw_only)  from leap.base import config as baseconfig  from leap.baseapp.permcheck import (is_pkexec_in_system, @@ -12,13 +14,18 @@ from leap.eip import exceptions as eip_exceptions  from leap.eip import specs as eipspecs  logger = logging.getLogger(name=__name__) +provider_ca_file = BRANDING.get('provider_ca_file', None)  class EIPConfig(baseconfig.JSONLeapConfig):      spec = eipspecs.eipconfig_spec      def _get_slug(self): -        return baseconfig.get_config_file('eip.json') +        dppath = baseconfig.get_default_provider_path() +        eipjsonpath = baseconfig.get_config_file( +            'eip-service.json', +            folder=dppath) +        return eipjsonpath      def _set_slug(self, *args, **kwargs):          raise AttributeError("you cannot set slug") @@ -48,6 +55,25 @@ def get_socket_path():      return socket_path +def get_eip_gateway(): +    """ +    return the first host in the list of hosts +    under gateways list +    """ +    eipconfig = EIPConfig() +    eipconfig.load() +    conf = eipconfig.get_config() +    gateways = conf.get('gateways', None) +    if len(gateways) > 0: +        # we just pick first +        gw = gateways[0] +    hosts = gw['hosts'] +    if len(hosts) > 0: +        return hosts[0] +    else: +        return "testprovider.example.org" + +  def build_ovpn_options(daemon=False, socket_path=None, **kwargs):      """      build a list of options @@ -84,9 +110,11 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs):          opts.append("%s" % verbosity)      # remote -    # XXX get remote from eip.json      opts.append('--remote') -    opts.append('testprovider.example.org') +    gw = get_eip_gateway() +    #gw = "springbokvpn.org" +    logger.debug('setting eip gateway to %s', gw) +    opts.append(str(gw))      opts.append('1194')      opts.append('udp') @@ -137,6 +165,7 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs):      #if daemon is True:          #opts.append('--daemon') +    logger.debug('vpn options: %s', opts)      return opts @@ -211,15 +240,30 @@ def check_vpn_keys():      logger.debug('client cert = %s', client_cert)      # if no keys, raise error. -    # should be catched by the ui and signal user. +    # it's catched by the ui and signal user. + +    if not os.path.isfile(provider_ca): +        # not there. let's try to copy. +        folder, filename = os.path.split(provider_ca) +        if not os.path.isdir(folder): +            mkdir_p(folder) +        if provider_ca_file: +            cacert = certs.where(provider_ca_file) +        with open(provider_ca, 'w') as pca: +            with open(cacert, 'r') as cac: +                pca.write(cac.read()) + +    if not os.path.isfile(provider_ca): +        logger.error('key file %s not found. aborting.', +                     provider_ca) +        raise eip_exceptions.EIPInitNoKeyFileError + +    if not os.path.isfile(client_cert): +        logger.error('key file %s not found. aborting.', +                     client_cert) +        raise eip_exceptions.EIPInitNoKeyFileError      for keyfile in (provider_ca, client_cert): -        if not os.path.isfile(keyfile): -            logger.error('key file %s not found. aborting.', -                         keyfile) -            raise eip_exceptions.EIPInitNoKeyFileError - -        # check proper permission on keys          # bad perms? try to fix them          try:              check_and_fix_urw_only(keyfile) diff --git a/src/leap/eip/constants.py b/src/leap/eip/constants.py index ce50f5e0..9af5a947 100644 --- a/src/leap/eip/constants.py +++ b/src/leap/eip/constants.py @@ -1,3 +1,3 @@  # not used anymore with the new JSONConfig.slug  EIP_CONFIG = "eip.json" -EIP_SERVICE_EXPECTED_PATH = "eip-service.json" +EIP_SERVICE_EXPECTED_PATH = "1/config/eip-service.json" diff --git a/src/leap/eip/eipconnection.py b/src/leap/eip/eipconnection.py index 3a879f01..4e240f16 100644 --- a/src/leap/eip/eipconnection.py +++ b/src/leap/eip/eipconnection.py @@ -4,7 +4,9 @@ EIP Connection Class  from __future__ import (absolute_import,)  import logging  import Queue +import sys +from leap.eip.checks import ProviderCertChecker  from leap.eip.checks import EIPConfigChecker  from leap.eip import config as eipconfig  from leap.eip import exceptions as eip_exceptions @@ -21,7 +23,10 @@ class EIPConnection(OpenVPNConnection):      Status updates (connected, bandwidth, etc) are signaled to the GUI.      """ -    def __init__(self, config_checker=EIPConfigChecker, *args, **kwargs): +    def __init__(self, +                 provider_cert_checker=ProviderCertChecker, +                 config_checker=EIPConfigChecker, +                 *args, **kwargs):          self.settingsfile = kwargs.get('settingsfile', None)          self.logfile = kwargs.get('logfile', None) @@ -29,6 +34,8 @@ class EIPConnection(OpenVPNConnection):          status_signals = kwargs.pop('status_signals', None)          self.status = EIPConnectionStatus(callbacks=status_signals) + +        self.provider_cert_checker = provider_cert_checker()          self.config_checker = config_checker()          host = eipconfig.get_socket_path() @@ -44,11 +51,25 @@ class EIPConnection(OpenVPNConnection):          run all eip checks previous to attempting a connection          """          logger.debug('running conductor checks') + +        def push_err(exc): +            # keep the original traceback! +            exc_traceback = sys.exc_info()[2] +            self.error_queue.put((exc, exc_traceback)) + +        try: +            # network (1) +            self.provider_cert_checker.run_all() +        except Exception as exc: +            push_err(exc)          try:              self.config_checker.run_all(skip_download=skip_download) +        except Exception as exc: +            push_err(exc) +        try:              self.run_openvpn_checks()          except Exception as exc: -            self.error_queue.put(exc) +            push_err(exc)      def connect(self):          """ @@ -82,6 +103,7 @@ class EIPConnection(OpenVPNConnection):          # XXX this separation does not          # make sense anymore after having          # merged Connection and Manager classes. +        # XXX GET RID OF THIS FUNCTION HERE!          try:              state = self.get_connection_state()          except eip_exceptions.ConnectionRefusedError: diff --git a/src/leap/eip/exceptions.py b/src/leap/eip/exceptions.py index 467be7fe..f048621f 100644 --- a/src/leap/eip/exceptions.py +++ b/src/leap/eip/exceptions.py @@ -40,6 +40,8 @@ class EIPClientError(Exception):      base EIPClient exception      """      critical = False +    failfirst = False +    warning = False  class CriticalError(EIPClientError): @@ -54,7 +56,7 @@ class Warning(EIPClientError):      """      just that, warnings      """ -    pass +    warning = True  class EIPNoPolkitAuthAgentAvailable(CriticalError): @@ -81,10 +83,21 @@ class EIPNoCommandError(EIPClientError):                     "<br/>(Might be a permissions problem)") +class EIPBadCertError(Warning): +    # XXX this should be critical and fail close +    message = "cert verification failed" +    usermessage = "there is a problem with provider certificate" + + +class LeapBadConfigFetchedError(Warning): +    message = "provider sent a malformed json file" +    usermessage = "an error occurred during configuratio of leap services" +  #  # errors still needing some love  # +  class EIPInitNoKeyFileError(CriticalError):      message = "No vpn keys found in the expected path"      usermessage = "We could not find your eip certs in the expected path" diff --git a/src/leap/eip/openvpnconnection.py b/src/leap/eip/openvpnconnection.py index b679a544..92ae9de9 100644 --- a/src/leap/eip/openvpnconnection.py +++ b/src/leap/eip/openvpnconnection.py @@ -114,11 +114,10 @@ to be triggered for each one of them.          """          try:              eip_config.check_vpn_keys() -        except eip_exceptions.EIPInitNoKeyFileError: -            self.missing_vpn_keyfile = True          except eip_exceptions.EIPInitBadKeyFilePermError: -            logger.error('error while checking vpn keys') -            self.bad_keyfile_perms = True +            logger.error('Bad VPN Keys permission!') +            # do nothing now +        # and raise the rest ...      def _launch_openvpn(self):          """ diff --git a/src/leap/eip/specs.py b/src/leap/eip/specs.py index e617574c..05aef590 100644 --- a/src/leap/eip/specs.py +++ b/src/leap/eip/specs.py @@ -1,15 +1,21 @@  from __future__ import (unicode_literals)  import os +from leap import __branding  from leap.base import config as baseconfig +PROVIDER_CA_CERT = __branding.get( +    'provider_ca_file', +    'testprovider-ca-cert.pem')  provider_ca_path = lambda: unicode(os.path.join(      baseconfig.get_default_provider_path(),      'keys', 'ca', -    'testprovider-ca-cert.pem' +    PROVIDER_CA_CERT  )) +PROVIDER_DOMAIN = __branding.get('provider_domain', 'testprovider.example.org') +  client_cert_path = lambda: unicode(os.path.join(      baseconfig.get_default_provider_path(), @@ -20,7 +26,7 @@ client_cert_path = lambda: unicode(os.path.join(  eipconfig_spec = {      'provider': {          'type': unicode, -        'default': u"testprovider.example.org", +        'default': u"%s" % PROVIDER_DOMAIN,          'required': True,      },      'transport': { diff --git a/src/leap/eip/tests/data.py b/src/leap/eip/tests/data.py index 284b398f..4da0e18f 100644 --- a/src/leap/eip/tests/data.py +++ b/src/leap/eip/tests/data.py @@ -1,21 +1,25 @@  from __future__ import unicode_literals  import os +from leap import __branding +  # sample data used in tests +PROVIDER = __branding.get('provider_domain') +  EIP_SAMPLE_JSON = { -    "provider": "testprovider.example.org", +    "provider": "%s" % PROVIDER,      "transport": "openvpn",      "openvpn_protocol": "tcp",      "openvpn_port": 80,      "openvpn_ca_certificate": os.path.expanduser(          "~/.config/leap/providers/" -        "testprovider.example.org/" -        "keys/ca/testprovider-ca-cert.pem"), +        "%s/" +        "keys/ca/testprovider-ca-cert.pem" % PROVIDER),      "openvpn_client_certificate": os.path.expanduser(          "~/.config/leap/providers/" -        "testprovider.example.org/" -        "keys/client/openvpn.pem"), +        "%s/" +        "keys/client/openvpn.pem" % PROVIDER),      "connect_on_login": True,      "block_cleartext_traffic": True,      "primary_gateway": "usa_west", diff --git a/src/leap/eip/tests/test_checks.py b/src/leap/eip/tests/test_checks.py index 952b10d2..42aa9cce 100644 --- a/src/leap/eip/tests/test_checks.py +++ b/src/leap/eip/tests/test_checks.py @@ -331,10 +331,10 @@ class ProviderCertCheckerHTTPSTests(BaseHTTPSServerTestCase, BaseLeapTest):              fetcher.get(uri, verify=True)              self.assertTrue(                  "SSL23_GET_SERVER_HELLO:unknown protocol" in exc.message) -        with self.assertRaises(requests.exceptions.SSLError) as exc: +        with self.assertRaises(eipexceptions.EIPBadCertError) as exc:              checker.is_https_working(uri=uri, verify=True)              self.assertTrue( -                "SSL23_GET_SERVER_HELLO:unknown protocol" in exc.message) +                "cert verification failed" in exc.message)          # get cacert from testing.https_server          cacert = where_cert('cacert.pem') diff --git a/src/leap/eip/tests/test_config.py b/src/leap/eip/tests/test_config.py index 60300770..f9f963dc 100644 --- a/src/leap/eip/tests/test_config.py +++ b/src/leap/eip/tests/test_config.py @@ -1,3 +1,4 @@ +import json  import os  import platform  import stat @@ -9,11 +10,17 @@ except ImportError:  #from leap.base import constants  #from leap.eip import config as eip_config +from leap import __branding as BRANDING +from leap.eip import config as eipconfig +from leap.eip.tests.data import EIP_SAMPLE_SERVICE  from leap.testing.basetest import BaseLeapTest  from leap.util.fileutil import mkdir_p  _system = platform.system() +PROVIDER = BRANDING.get('provider_domain') +PROVIDER_SHORTNAME = BRANDING.get('short_name') +  class EIPConfigTest(BaseLeapTest): @@ -39,6 +46,14 @@ class EIPConfigTest(BaseLeapTest):          open(tfile, 'wb').close()          os.chmod(tfile, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) +    def write_sample_eipservice(self): +        conf = eipconfig.EIPConfig() +        folder, f = os.path.split(conf.filename) +        if not os.path.isdir(folder): +            mkdir_p(folder) +        with open(conf.filename, 'w') as fd: +            fd.write(json.dumps(EIP_SAMPLE_SERVICE)) +      def get_expected_openvpn_args(self):          args = []          username = self.get_username() @@ -51,7 +66,7 @@ class EIPConfigTest(BaseLeapTest):          args.append('--persist-tun')          args.append('--persist-key')          args.append('--remote') -        args.append('testprovider.example.org') +        args.append('%s' % eipconfig.get_eip_gateway())          # XXX get port!?          args.append('1194')          # XXX get proto @@ -80,23 +95,23 @@ class EIPConfigTest(BaseLeapTest):          args.append(os.path.join(              self.home,              '.config', 'leap', 'providers', -            'testprovider.example.org', +            '%s' % PROVIDER,              'keys', 'client',              'openvpn.pem'))          args.append('--key')          args.append(os.path.join(              self.home,              '.config', 'leap', 'providers', -            'testprovider.example.org', +            '%s' % PROVIDER,              'keys', 'client',              'openvpn.pem'))          args.append('--ca')          args.append(os.path.join(              self.home,              '.config', 'leap', 'providers', -            'testprovider.example.org', +            '%s' % PROVIDER,              'keys', 'ca', -            'testprovider-ca-cert.pem')) +            '%s-cacert.pem' % PROVIDER_SHORTNAME))          return args      # build command string @@ -107,6 +122,7 @@ class EIPConfigTest(BaseLeapTest):      def test_build_ovpn_command_empty_config(self):          self.touch_exec() +        self.write_sample_eipservice()          from leap.eip import config as eipconfig          from leap.util.fileutil import which          path = os.environ['PATH'] | 
