summaryrefslogtreecommitdiff
path: root/src/leap/base/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/base/config.py')
-rw-r--r--src/leap/base/config.py252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/leap/base/config.py b/src/leap/base/config.py
new file mode 100644
index 00000000..dbd2e2c0
--- /dev/null
+++ b/src/leap/base/config.py
@@ -0,0 +1,252 @@
+"""
+Configuration Base Class
+"""
+import configuration # python configuration module, not local!
+import grp
+import json
+import logging
+import requests
+import socket
+import os
+
+logger = logging.getLogger(name=__name__)
+logger.setLevel('DEBUG')
+
+from leap.util.fileutil import (mkdir_p)
+
+
+class BaseLeapConfig(object):
+ slug = None
+
+ # XXX we have to enforce that we have a slug (via interface)
+ # get property getter that raises NI..
+
+ def save(self):
+ raise NotImplementedError("abstract base class")
+
+ def load(self):
+ raise NotImplementedError("abstract base class")
+
+ def get_config(self, *kwargs):
+ raise NotImplementedError("abstract base class")
+
+ #XXX todo: enable this property after
+ #fixing name clash with "config" in use at
+ #vpnconnection
+
+ #@property
+ #def config(self):
+ #return self.get_config()
+
+ def get_value(self, *kwargs):
+ raise NotImplementedError("abstract base class")
+
+
+class JSONLeapConfig(BaseLeapConfig):
+
+ def __init__(self, *args, **kwargs):
+ # sanity check
+ assert self.slug is not None
+ assert self.spec is not None
+ assert issubclass(self.spec, configuration.Configuration)
+
+ self._config = self.spec()
+ self._config.parse_args(list(args))
+
+ # mandatory baseconfig interface
+
+ def save(self, to=None):
+ if to is None:
+ to = self.filename
+ self._config.serialize(to)
+
+ def load(self, fromfile=None):
+ # load should get a much more generic
+ # argument. it could be, f.i., from_uri,
+ # and call to Fetcher
+
+ if fromfile is None:
+ fromfile = self.filename
+ self._config.deserialize(fromfile)
+
+ def get_config(self):
+ return self._config.config
+
+ # public methods
+
+ def get_filename(self):
+ return self._slug_to_filename()
+
+ @property
+ def filename(self):
+ return self.get_filename()
+
+ def _slug_to_filename(self):
+ # is this going to work in winland if slug is "foo/bar" ?
+ folder, filename = os.path.split(self.slug)
+ # XXX fix import
+ config_file = get_config_file(filename, folder)
+ return config_file
+
+#
+# utility functions
+#
+# (might be moved to some class as we see fit, but
+# let's remain functional for a while)
+#
+
+
+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
+
+
+# json stuff
+
+# XXX merge with JSONConfig
+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()
+ return json.load(open(fpath))
+
+ else:
+ #TODO: add validity checks of file
+ return json.load(open(config_file))
+
+
+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
+
+#
+# XXX merge conflict
+# tests are still using this deprecated Configuration object.
+# 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:
+ 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