From e9a817ceadab842ec5382e074e4d7861dbd2b898 Mon Sep 17 00:00:00 2001 From: antialias Date: Tue, 21 Aug 2012 15:27:29 -0700 Subject: pep --- src/leap/eip/exceptions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/leap/eip/exceptions.py b/src/leap/eip/exceptions.py index ac61f42b..3719c605 100644 --- a/src/leap/eip/exceptions.py +++ b/src/leap/eip/exceptions.py @@ -61,5 +61,3 @@ class EIPInitNoKeyFileError(Exception): class EIPInitBadKeyFilePermError(Exception): pass - - -- cgit v1.2.3 From 9891fc2f6869db7fc56503087ce124d74f5fc3b7 Mon Sep 17 00:00:00 2001 From: antialias Date: Wed, 22 Aug 2012 14:01:22 -0700 Subject: moved help functions from eip/config.py to base/configuration.py. --- src/leap/base/configuration.py | 98 ++++++++++++++++++++++++++++++++++++++++++ src/leap/eip/config.py | 86 ++---------------------------------- 2 files changed, 102 insertions(+), 82 deletions(-) diff --git a/src/leap/base/configuration.py b/src/leap/base/configuration.py index 243e2e2c..31092f8a 100644 --- a/src/leap/base/configuration.py +++ b/src/leap/base/configuration.py @@ -2,6 +2,14 @@ Configuration Base Class """ +import grp +import logging +import requests +import os + +logger = logging.getLogger(name=__name__) +logger.setLevel('DEBUG') + class Configuration(object): """ @@ -9,3 +17,93 @@ class Configuration(object): (txt vs. sqlite) will be done, but let's stub it now. """ pass + + +def get_config_dir(): + """ + get the base dir for all leap config + @rparam: config path + @rtype: string + """ + # TODO + # check for $XDG_CONFIG_HOME var? + # get a more sensible path for win/mac + # kclair: opinion? ^^ + return os.path.expanduser( + os.path.join('~', + '.config', + 'leap')) + + +def get_config_file(filename, folder=None): + """ + concatenates the given filename + with leap config dir. + @param filename: name of the file + @type filename: string + @rparam: full path to config file + """ + path = [] + path.append(get_config_dir()) + if folder is not None: + path.append(folder) + path.append(filename) + return os.path.join(*path) + + +def get_default_provider_path(): + default_subpath = os.path.join("providers", + "default") + default_provider_path = get_config_file( + '', + folder=default_subpath) + return default_provider_path + + +def validate_ip(ip_str): + """ + raises exception if the ip_str is + not a valid representation of an ip + """ + socket.inet_aton(ip_str) + + +def get_username(): + return os.getlogin() + + +def get_groupname(): + gid = os.getgroups()[-1] + return grp.getgrgid(gid).gr_name + + +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: + 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() + config_file = open(fpath) + + config = json.load(config_file) + + return config + + +def get_definition_file(url=None): + """ + """ + #TODO: determine good default location of definition file. + r = requests.get(url) + return r.json diff --git a/src/leap/eip/config.py b/src/leap/eip/config.py index f38268e2..b461422a 100644 --- a/src/leap/eip/config.py +++ b/src/leap/eip/config.py @@ -8,6 +8,10 @@ import socket from leap.util.fileutil import (which, mkdir_p, check_and_fix_urw_only) +from leap.base.configuration import (get_default_provider_path, + get_config_file, + get_username, + get_groupname) from leap.baseapp.permcheck import (is_pkexec_in_system, is_auth_agent_running) from leap.eip import exceptions as eip_exceptions @@ -32,55 +36,6 @@ ca {LEAP_EIP_KEYS} """ -def get_config_dir(): - """ - get the base dir for all leap config - @rparam: config path - @rtype: string - """ - # TODO - # check for $XDG_CONFIG_HOME var? - # get a more sensible path for win/mac - # kclair: opinion? ^^ - return os.path.expanduser( - os.path.join('~', - '.config', - 'leap')) - - -def get_config_file(filename, folder=None): - """ - concatenates the given filename - with leap config dir. - @param filename: name of the file - @type filename: string - @rparam: full path to config file - """ - path = [] - path.append(get_config_dir()) - if folder is not None: - path.append(folder) - path.append(filename) - return os.path.join(*path) - - -def get_default_provider_path(): - default_subpath = os.path.join("providers", - "default") - default_provider_path = get_config_file( - '', - folder=default_subpath) - return default_provider_path - - -def validate_ip(ip_str): - """ - raises exception if the ip_str is - not a valid representation of an ip - """ - socket.inet_aton(ip_str) - - def check_or_create_default_vpnconf(config): """ checks that a vpn config file @@ -158,15 +113,6 @@ def check_or_create_default_vpnconf(config): f.write(ovpn_config) -def get_username(): - return os.getlogin() - - -def get_groupname(): - gid = os.getgroups()[-1] - return grp.getgrgid(gid).gr_name - - def build_ovpn_options(daemon=False): """ build a list of options @@ -412,27 +358,3 @@ def check_vpn_keys(config): check_and_fix_urw_only(keyfile) except OSError: raise eip_exceptions.EIPInitBadKeyFilePermError - - -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: - 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() - config_file = open(fpath) - - config = json.load(config_file) - - return config -- cgit v1.2.3 From dc10833bedcdecf081a7c79678614c5521445164 Mon Sep 17 00:00:00 2001 From: antialias Date: Wed, 22 Aug 2012 19:47:41 -0700 Subject: grabs a definition.json file if one isn't present. includes some basic error handling and tests. uses the requests library for network interactions and mocks for simulating network states. --- src/leap/base/configuration.py | 67 +++++++++--- src/leap/base/tests/test_configuration.py | 169 ++++++++++++++++++++++++++++++ src/leap/baseapp/mainwindow.py | 13 +++ src/leap/eip/tests/test_config.py | 104 ------------------ 4 files changed, 237 insertions(+), 116 deletions(-) create mode 100644 src/leap/base/tests/test_configuration.py diff --git a/src/leap/base/configuration.py b/src/leap/base/configuration.py index 31092f8a..155324df 100644 --- a/src/leap/base/configuration.py +++ b/src/leap/base/configuration.py @@ -3,20 +3,59 @@ Configuration Base Class """ import grp +import json import logging import requests import os +from leap.util.fileutil import mkdir_p + logger = logging.getLogger(name=__name__) logger.setLevel('DEBUG') class Configuration(object): """ - I have no idea how configuration - (txt vs. sqlite) will be done, but let's stub it now. + All configurations (providers et al) will be managed in this class. """ - pass + def __init__(self, provider_url=None): + try: + 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.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 def get_config_dir(): @@ -87,6 +126,7 @@ def get_config_json(config_file=None): @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) @@ -94,16 +134,19 @@ def get_config_json(config_file=None): mkdir_p(dpath) with open(fpath, 'wb') as configfile: configfile.flush() - config_file = open(fpath) - - config = json.load(config_file) + return json.load(open(fpath)) - return config + else: + #TODO: add validity checks of file + return json.load(open(config_file)) -def get_definition_file(url=None): - """ +def is_internet_up(): + """TODO: Build more robust network diagnosis capabilities """ - #TODO: determine good default location of definition file. - r = requests.get(url) - return r.json + try: + response = requests.get('http://128.30.52.45', timeout=1) + return True + except requests.Timeout as err: + pass + return False diff --git a/src/leap/base/tests/test_configuration.py b/src/leap/base/tests/test_configuration.py new file mode 100644 index 00000000..17c8ed1f --- /dev/null +++ b/src/leap/base/tests/test_configuration.py @@ -0,0 +1,169 @@ +import mock +import os +import platform +import requests +import tempfile + +from leap.testing.basetest import BaseLeapTest +from leap.base.configuration import Configuration + +from leap.base import configuration as config + +try: + import unittest2 as unittest +except ImportError: + import unittest + +_system = platform.system() + + +class DefinitionTestCase(BaseLeapTest): + + __name__ = "provider_config_tests" + + def setUp(self): + self.old_home = os.environ['HOME'] + self.home = tempfile.mkdtemp() + os.environ['HOME'] = self.home + pass + + #Not correct removing the test directories but will be refactor out + #with kali's new test classes + def tearDown(self): + os.environ['HOME'] = self.old_home + pass + + def test_complete_file(self): + with mock.patch.object(requests, "get") as mock_method: + mock_method.return_value.status_code = 200 + mock_method.return_value.json = { + u'api_uri': u'https://api.testprovider.org/', + u'api_version': u'0.1.0', + u'ca_cert': u'8aab80ae4326fd30721689db813733783fe0bd7e', + u'ca_cert_uri': u'https://testprovider.org/cacert.pem', + u'description': {u'en': u'This is a test provider'}, + u'display_name': {u'en': u'Test Provider'}, + u'domain': u'testprovider.org', + u'enrollment_policy': u'open', + u'public_key': u'cb7dbd679f911e85bc2e51bd44afd7308ee19c21', + u'serial': 1, + u'services': [u'eip'], + u'version': u'0.1.0'} + cf = Configuration("http://localhost/") + self.assertIn('default', cf.providers) + + def test_connection_error(self): + with mock.patch.object(requests, "get") as mock_method: + mock_method.side_effect = requests.ConnectionError + cf = Configuration() + self.assertIsInstance(cf.error, str) + + def test_file_not_found(self): + with mock.patch.object(requests, "get") as mock_method: + mock_method.side_effect = requests.HTTPError + cf = Configuration() + self.assertIsInstance(cf.error, str) + + def test_invalid_url(self): + cf = Configuration("ht") + self.assertTrue(cf.error) + + +class ConfigHelperFunctions(BaseLeapTest): + + __name__ = "config_helper_tests" + + # + # tests + # + + # XXX fixme! /home/user should + # be replaced for proper home lookup. + + @unittest.skipUnless(_system == "Linux", "linux only") + def test_lin_get_config_file(self): + """ + config file path where expected? (linux) + """ + self.assertEqual( + config.get_config_file( + 'test', folder="foo/bar"), + '/home/%s/.config/leap/foo/bar/test' % + config.get_username()) + + @unittest.skipUnless(_system == "Darwin", "mac only") + def test_mac_get_config_file(self): + """ + config file path where expected? (mac) + """ + self._missing_test_for_plat(do_raise=True) + + @unittest.skipUnless(_system == "Windows", "win only") + def test_win_get_config_file(self): + """ + config file path where expected? + """ + self._missing_test_for_plat(do_raise=True) + + # provider paths + + @unittest.skipUnless(_system == "Linux", "linux only") + def test_get_default_provider_path(self): + """ + is default provider path ok? + """ + self.assertEqual( + config.get_default_provider_path(), + '/home/%s/.config/leap/providers/default/' % + config.get_username()) + + # validate ip + + def test_validate_ip(self): + """ + check our ip validation + """ + config.validate_ip('3.3.3.3') + with self.assertRaises(socket.error): + config.validate_ip('255.255.255.256') + with self.assertRaises(socket.error): + config.validate_ip('foobar') + + @unittest.skip + def test_validate_domain(self): + """ + code to be written yet + """ + pass + + # + # XXX hey, I'm raising exceptions here + # on purpose. just wanted to make sure + # that the skip stuff is doing it right. + # If you're working on win/macos tests, + # feel free to remove tests that you see + # are too redundant. + + @unittest.skipUnless(_system == "Linux", "linux only") + def test_lin_get_config_dir(self): + """ + nice config dir? (linux) + """ + self.assertEqual( + config.get_config_dir(), + '/home/%s/.config/leap' % + self.get_username()) + + @unittest.skipUnless(_system == "Darwin", "mac only") + def test_mac_get_config_dir(self): + """ + nice config dir? (mac) + """ + self._missing_test_for_plat(do_raise=True) + + @unittest.skipUnless(_system == "Windows", "win only") + def test_win_get_config_dir(self): + """ + nice config dir? (win) + """ + self._missing_test_for_plat(do_raise=True) diff --git a/src/leap/baseapp/mainwindow.py b/src/leap/baseapp/mainwindow.py index bc844437..912a51b6 100644 --- a/src/leap/baseapp/mainwindow.py +++ b/src/leap/baseapp/mainwindow.py @@ -11,6 +11,8 @@ from PyQt4.QtGui import (QMainWindow, QWidget, QVBoxLayout, QMessageBox, QTextBrowser, qApp) from PyQt4.QtCore import (pyqtSlot, pyqtSignal, QTimer) +from leap.base.configuration import Configuration + from leap.baseapp.dialogs import ErrorDialog from leap.eip import exceptions as eip_exceptions @@ -18,6 +20,9 @@ from leap.eip.eipconnection import EIPConnection from leap.gui import mainwindow_rc +#TODO: Get rid of this and do something clever +DEFAULT_PROVIDER_URL = "http://localhost/definition.json" + class LeapWindow(QMainWindow): #XXX tbd: refactor into model / view / controller @@ -30,6 +35,8 @@ class LeapWindow(QMainWindow): super(LeapWindow, self).__init__() self.debugmode = getattr(opts, 'debug', False) + self.configuration = Configuration() + self.vpn_service_started = False self.createWindowHeader() @@ -81,6 +88,12 @@ class LeapWindow(QMainWindow): # bunch of self checks. # XXX move somewhere else alltogether. # + if self.configuration.error is True: + dialog = ErrorDialog() + dialog.criticalMessage( + 'There is a problem with the default ' + 'definition.json file', + 'error') if self.conductor.missing_provider is True: dialog = ErrorDialog() diff --git a/src/leap/eip/tests/test_config.py b/src/leap/eip/tests/test_config.py index b4ad66e5..0e1a3a01 100644 --- a/src/leap/eip/tests/test_config.py +++ b/src/leap/eip/tests/test_config.py @@ -82,101 +82,6 @@ class EIPConfigTest(BaseLeapTest): username) return args - # - # tests - # - - # XXX fixme! /home/user should - # be replaced for proper home lookup. - - @unittest.skipUnless(_system == "Linux", "linux only") - def test_lin_get_config_file(self): - """ - config file path where expected? (linux) - """ - self.assertEqual( - config.get_config_file( - 'test', folder="foo/bar"), - '/home/%s/.config/leap/foo/bar/test' % - self.get_username()) - - @unittest.skipUnless(_system == "Darwin", "mac only") - def test_mac_get_config_file(self): - """ - config file path where expected? (mac) - """ - self._missing_test_for_plat(do_raise=True) - - @unittest.skipUnless(_system == "Windows", "win only") - def test_win_get_config_file(self): - """ - config file path where expected? - """ - self._missing_test_for_plat(do_raise=True) - - # - # XXX hey, I'm raising exceptions here - # on purpose. just wanted to make sure - # that the skip stuff is doing it right. - # If you're working on win/macos tests, - # feel free to remove tests that you see - # are too redundant. - - @unittest.skipUnless(_system == "Linux", "linux only") - def test_lin_get_config_dir(self): - """ - nice config dir? (linux) - """ - self.assertEqual( - config.get_config_dir(), - '/home/%s/.config/leap' % - self.get_username()) - - @unittest.skipUnless(_system == "Darwin", "mac only") - def test_mac_get_config_dir(self): - """ - nice config dir? (mac) - """ - self._missing_test_for_plat(do_raise=True) - - @unittest.skipUnless(_system == "Windows", "win only") - def test_win_get_config_dir(self): - """ - nice config dir? (win) - """ - self._missing_test_for_plat(do_raise=True) - - # provider paths - - @unittest.skipUnless(_system == "Linux", "linux only") - def test_get_default_provider_path(self): - """ - is default provider path ok? - """ - self.assertEqual( - config.get_default_provider_path(), - '/home/%s/.config/leap/providers/default/' % - self.get_username()) - - # validate ip - - def test_validate_ip(self): - """ - check our ip validation - """ - config.validate_ip('3.3.3.3') - with self.assertRaises(socket.error): - config.validate_ip('255.255.255.256') - with self.assertRaises(socket.error): - config.validate_ip('foobar') - - @unittest.skip - def test_validate_domain(self): - """ - code to be written yet - """ - pass - # build command string # these tests are going to have to check # many combinations. we should inject some @@ -191,15 +96,6 @@ class EIPConfigTest(BaseLeapTest): self.assertEqual(command, 'openvpn') self.assertEqual(args, self.get_expected_openvpn_args()) - # json config - - def test_get_config_json(self): - config_js = config.get_config_json() - self.assertTrue(isinstance(config_js, dict)) - self.assertTrue('transport' in config_js) - self.assertTrue('provider' in config_js) - self.assertEqual(config_js['provider'], "testprovider.org") - if __name__ == "__main__": unittest.main() -- cgit v1.2.3