From 808f9d3542e21c819beb8fe72224f000ae2e019c Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Thu, 31 Aug 2017 10:58:59 +0200 Subject: [feat] expose an API to set/get/list gateway preferences - Related: #9010 --- docs/vpn/index.rst | 2 +- src/leap/bitmask/cli/vpn.py | 2 +- src/leap/bitmask/core/dispatcher.py | 14 +++++++++ src/leap/bitmask/core/service.py | 3 +- src/leap/bitmask/vpn/service.py | 57 ++++++++++++++++++++++++------------- ui/app/lib/bitmask.js | 40 ++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/docs/vpn/index.rst b/docs/vpn/index.rst index 7bb4799a..0ec660fe 100644 --- a/docs/vpn/index.rst +++ b/docs/vpn/index.rst @@ -22,7 +22,7 @@ wants to manually override the selection, the only way to do this for the ``0.10`` version of Bitmask is to add a section to the ``bitmaskd.cfg`` configuration file:: - [vpn_prefs] + [vpn] locations = ["rio__br"] countries = ["BR", "AR", "UY"] diff --git a/src/leap/bitmask/cli/vpn.py b/src/leap/bitmask/cli/vpn.py index cf4cf169..6917b15d 100644 --- a/src/leap/bitmask/cli/vpn.py +++ b/src/leap/bitmask/cli/vpn.py @@ -47,7 +47,7 @@ SUBCOMMANDS: '''.format(name=command.appname) commands = ['stop', 'install', 'uninstall', - 'enable', 'disable'] + 'enable', 'disable', 'locations', 'countries'] def start(self, raw_args): parser = argparse.ArgumentParser( diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py index 508a925d..363594ca 100644 --- a/src/leap/bitmask/core/dispatcher.py +++ b/src/leap/bitmask/core/dispatcher.py @@ -237,6 +237,20 @@ class VPNCmd(SubCommand): d = vpn.do_list() return d + @register_method('list') + def do_LOCATIONS(self, vpn, *parts): + if len(parts) > 2: + return vpn.do_set_locations(parts[2:]) + + return vpn.do_get_locations() + + @register_method('list') + def do_COUNTRIES(self, vpn, *parts): + if len(parts) > 2: + return vpn.do_set_countries(parts[2:]) + + return vpn.do_get_countries() + class MailCmd(SubCommand): diff --git a/src/leap/bitmask/core/service.py b/src/leap/bitmask/core/service.py index e823d829..026e51d9 100644 --- a/src/leap/bitmask/core/service.py +++ b/src/leap/bitmask/core/service.py @@ -208,7 +208,8 @@ class BitmaskBackend(configurable.ConfigurableService): def _init_vpn(self): if HAS_VPN: - self._maybe_init_service('vpn', VPNService) + cfg = self.get_config_section('vpn') + self._maybe_init_service('vpn', VPNService, cfg) def _init_zmq(self): zs = _zmq.ZMQServerService(self) diff --git a/src/leap/bitmask/vpn/service.py b/src/leap/bitmask/vpn/service.py index 6588e1d5..c410f7e4 100644 --- a/src/leap/bitmask/vpn/service.py +++ b/src/leap/bitmask/vpn/service.py @@ -50,7 +50,7 @@ class VPNService(HookableService): _last_vpn_path = os.path.join('leap', 'last_vpn') log = Logger() - def __init__(self, basepath=None): + def __init__(self, cfg, basepath=None): """ Initialize VPN service. This launches both the firewall and the vpn. """ @@ -59,12 +59,24 @@ class VPNService(HookableService): self._tunnel = None self._firewall = FirewallManager([]) self._domain = '' + self._cfg = cfg if basepath is None: self._basepath = get_path_prefix() else: self._basepath = basepath + try: + _cco = self._cfg.get('countries', "") + self._cco = json.loads(_cco) + except ValueError: + self._cco = [] + try: + _loc = self._cfg.get('locations', "") + self._loc = json.loads(_loc) + except ValueError: + self._loc = [] + if helpers.check() and self._firewall.is_up(): self._firewall.stop() @@ -194,10 +206,29 @@ class VPNService(HookableService): config = yield bonafide.do_provider_read(provider, 'eip') except ValueError: continue - gateways = self._gateways(config) + gateways = GatewaySelector( + config.gateways, config.locations, + preferred={'cc': self._cco, 'loc': self._loc} + ) provider_dict[provider] = gateways.get_sorted_gateways() defer.returnValue(provider_dict) + def do_set_locations(self, locations): + self._loc = locations + self._cfg.set('locations', json.dumps(locations)) + return {'locations': 'ok'} + + def do_get_locations(self): + return self._loc + + def do_set_countries(self, countries): + self._cco = countries + self._cfg.set('countries', json.dumps(countries)) + return {'countries': 'ok'} + + def do_get_countries(self): + return self._cco + @defer.inlineCallbacks def _setup(self, provider): """Set up ConfiguredTunnel for a specified provider. @@ -208,7 +239,10 @@ class VPNService(HookableService): bonafide = self.parent.getServiceNamed('bonafide') config = yield bonafide.do_provider_read(provider, 'eip') - sorted_gateways = self._gateways(config).select_gateways() + sorted_gateways = GatewaySelector( + config.gateways, config.locations, + preferred={'cc': self._cco, 'loc': self._loc} + ).select_gateways() extra_flags = config.openvpn_configuration @@ -231,23 +265,6 @@ class VPNService(HookableService): provider, remotes, cert_path, key_path, ca_path, extra_flags) self._firewall = FirewallManager(remotes) - def _gateways(self, config): - try: - _cco = self.parent.get_config('vpn_prefs', 'countries', "") - pref_cco = json.loads(_cco) - except ValueError: - pref_cco = [] - try: - _loc = self.parent.get_config('vpn_prefs', 'locations', "") - pref_loc = json.loads(_loc) - except ValueError: - pref_loc = [] - - return GatewaySelector( - config.gateways, config.locations, - preferred={'cc': pref_cco, 'loc': pref_loc} - ) - def _cert_expires(self, provider): path = os.path.join( self._basepath, "leap", "providers", provider, diff --git a/ui/app/lib/bitmask.js b/ui/app/lib/bitmask.js index bfdf0501..7a97319b 100644 --- a/ui/app/lib/bitmask.js +++ b/ui/app/lib/bitmask.js @@ -289,6 +289,46 @@ var bitmask = function(){ uninstall: function() { return call(['vpn', 'uninstall']) } + + /** + * List VPN gateways + * + * They will be sorted in the order that they will be used + * + * @return {Promise<{provider_name: [{'name': string, + * 'country_code': string, + * 'location': string, + * ...}]}> + */ + list: function() { + return call(['vpn', 'list']) + } + + /** + * Get/set the location preference for the gateways + * + * @param {list} Order of preference of locations. + * If it's missing it will return the existing location list + */ + locations: function(locations) { + if (typeof locations !== 'list') { + locations = []; + } + return call(['vpn', 'locations'].concat(locations)) + } + + /** + * Get/set the country preference for the gateways + * + * @param {list} Order of preference of countries. + * If it's missing it will return the existing country list + */ + countries: function(countries) { + if (typeof countries !== 'list') { + countries = []; + } + return call(['vpn', 'countries'].concat(countries)) + } }, mail: { -- cgit v1.2.3