diff options
-rw-r--r-- | changes/feature_2925_osx-use-cocoasudo | 1 | ||||
-rw-r--r-- | data/images/leap-client.tiff | bin | 0 -> 3598 bytes | |||
-rw-r--r-- | setup.cfg | 4 | ||||
-rw-r--r-- | src/leap/services/eip/eipconfig.py | 42 | ||||
-rw-r--r-- | src/leap/services/eip/tests/test_vpngatewayselector.py | 86 | ||||
-rw-r--r-- | src/leap/services/eip/vpnlaunchers.py | 33 |
6 files changed, 137 insertions, 29 deletions
diff --git a/changes/feature_2925_osx-use-cocoasudo b/changes/feature_2925_osx-use-cocoasudo new file mode 100644 index 00000000..b87a8de1 --- /dev/null +++ b/changes/feature_2925_osx-use-cocoasudo @@ -0,0 +1 @@ + o Use cocoasudo in place of osascript for osx privilege escalation during openvpn launch. diff --git a/data/images/leap-client.tiff b/data/images/leap-client.tiff Binary files differnew file mode 100644 index 00000000..71c95b0d --- /dev/null +++ b/data/images/leap-client.tiff diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 76380751..00000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# remove this file when tests listed below are working -[nosetests] -exclude-dir=src/leap/services/eip/tests - src/leap/crypto/tests diff --git a/src/leap/services/eip/eipconfig.py b/src/leap/services/eip/eipconfig.py index a85fe64a..97eb3dfb 100644 --- a/src/leap/services/eip/eipconfig.py +++ b/src/leap/services/eip/eipconfig.py @@ -21,7 +21,6 @@ Provider configuration import logging import os import re -import datetime import time import ipaddr @@ -39,17 +38,21 @@ class VPNGatewaySelector(object): VPN Gateway selector. """ - def __init__(self, eipconfig): + def __init__(self, eipconfig, tz_offset=None): ''' Constructor for VPNGatewaySelector. :param eipconfig: a valid EIP Configuration. :type eipconfig: EIPConfig + :param tz_offset: use this offset as a local distance to GMT. + :type tz_offset: int ''' leap_assert_type(eipconfig, EIPConfig) - self._local_offset = 0 # defaults to GMT - self._local_timezone = None - self._set_local_offset() + + self._local_offset = tz_offset + if tz_offset is None: + self._local_offset = self._get_local_offset() + self._eipconfig = eipconfig def get_gateways(self): @@ -89,21 +92,29 @@ class VPNGatewaySelector(object): :returns: distance between local offset and param offset. :rtype: int ''' - delta1 = datetime.timedelta(hours=offset) - delta2 = self._local_offset - diff = abs(delta1 - delta2) - hours = diff.seconds / (60 * 60) - return hours - - def _set_local_offset(self): + timezones = range(-11, 13) + tz1 = offset + tz2 = self._local_offset + distance = abs(timezones.index(tz1) - timezones.index(tz2)) + if distance > 12: + if tz1 < 0: + distance = timezones.index(tz1) + timezones[::-1].index(tz2) + else: + distance = timezones[::-1].index(tz1) + timezones.index(tz2) + + return distance + + def _get_local_offset(self): ''' - Sets the distance between GMT and the local timezone. + Returns the distance between GMT and the local timezone. + + :rtype: int ''' local_offset = time.timezone if time.daylight: local_offset = time.altzone - self._local_offset = datetime.timedelta(seconds=-local_offset) + return local_offset / 3600 class EIPConfig(BaseConfig): @@ -176,7 +187,7 @@ class EIPConfig(BaseConfig): index = 0 logger.warning("Provided an unknown gateway index %s, " + "defaulting to 0") - ip_addr_str = gateways[0]["ip_address"] + ip_addr_str = gateways[index]["ip_address"] try: ipaddr.IPAddress(ip_addr_str) @@ -233,6 +244,7 @@ if __name__ == "__main__": if eipconfig.load("leap/providers/bitmask.net/eip-service.json"): print eipconfig.get_clusters() print eipconfig.get_gateways() + print eipconfig.get_locations() print eipconfig.get_openvpn_configuration() print eipconfig.get_serial() print eipconfig.get_version() diff --git a/src/leap/services/eip/tests/test_vpngatewayselector.py b/src/leap/services/eip/tests/test_vpngatewayselector.py new file mode 100644 index 00000000..250e6e00 --- /dev/null +++ b/src/leap/services/eip/tests/test_vpngatewayselector.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# test_vpngatewayselector.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/>. +""" +tests for vpngatewayselector +""" + +import unittest + +from leap.services.eip.eipconfig import EIPConfig, VPNGatewaySelector +from leap.common.testing.basetest import BaseLeapTest +from mock import Mock + + +sample_gateways = [ + {u'host': u'gateway1.com', + u'ip_address': u'1.2.3.4', + u'location': u'location1'}, + {u'host': u'gateway2.com', + u'ip_address': u'2.3.4.5', + u'location': u'location2'}, + {u'host': u'gateway3.com', + u'ip_address': u'3.4.5.6', + u'location': u'location3'} +] + +sample_locations = { + u'location1': {u'timezone': u'2'}, + u'location2': {u'timezone': u'-7'}, + u'location3': {u'timezone': u'-4'} +} + + +class VPNGatewaySelectorTest(BaseLeapTest): + """ + VPNGatewaySelector's tests. + """ + def setUp(self): + self.eipconfig = EIPConfig() + self.eipconfig.get_gateways = Mock(return_value=sample_gateways) + self.eipconfig.get_locations = Mock(return_value=sample_locations) + + def tearDown(self): + pass + + def test_correct_order_gmt(self): + gateway_selector = VPNGatewaySelector(self.eipconfig, 0) + gateways = gateway_selector.get_gateways() + self.assertEqual(gateways, [u'1.2.3.4', u'3.4.5.6', u'2.3.4.5']) + + def test_correct_order_gmt_minus_3(self): + gateway_selector = VPNGatewaySelector(self.eipconfig, -3) + gateways = gateway_selector.get_gateways() + self.assertEqual(gateways, [u'3.4.5.6', u'2.3.4.5', u'1.2.3.4']) + + def test_correct_order_gmt_minus_7(self): + gateway_selector = VPNGatewaySelector(self.eipconfig, -7) + gateways = gateway_selector.get_gateways() + self.assertEqual(gateways, [u'2.3.4.5', u'3.4.5.6', u'1.2.3.4']) + + def test_correct_order_gmt_plus_5(self): + gateway_selector = VPNGatewaySelector(self.eipconfig, 5) + gateways = gateway_selector.get_gateways() + self.assertEqual(gateways, [u'1.2.3.4', u'3.4.5.6', u'2.3.4.5']) + + def test_correct_order_gmt_plus_10(self): + gateway_selector = VPNGatewaySelector(self.eipconfig, 10) + gateways = gateway_selector.get_gateways() + self.assertEqual(gateways, [u'2.3.4.5', u'1.2.3.4', u'3.4.5.6']) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py index 56df0b1c..570a7893 100644 --- a/src/leap/services/eip/vpnlaunchers.py +++ b/src/leap/services/eip/vpnlaunchers.py @@ -458,12 +458,12 @@ class DarwinVPNLauncher(VPNLauncher): VPN launcher for the Darwin Platform """ - OSASCRIPT_BIN = '/usr/bin/osascript' - OSX_ASADMIN = "do shell script \"%s\" with administrator privileges" + COCOASUDO = "cocoasudo" + # XXX need magic translate for this string + SUDO_MSG = ("LEAP needs administrative privileges to run " + "Encrypted Internet.") INSTALL_PATH = "/Applications/LEAP\ Client.app" - # OPENVPN_BIN = "/%s/Contents/Resources/openvpn.leap" % ( - # self.INSTALL_PATH,) OPENVPN_BIN = 'openvpn.leap' OPENVPN_PATH = "%s/Contents/Resources/openvpn" % (INSTALL_PATH,) @@ -481,9 +481,25 @@ class DarwinVPNLauncher(VPNLauncher): """ to = kls.OPENVPN_PATH cmd = "#!/bin/sh\nmkdir -p %s\ncp \"%s/\"* %s" % (to, frompath, to) - #return kls.OSX_ASADMIN % cmd return cmd + def get_cocoasudo_cmd(self): + """ + Returns a string with the cocoasudo command needed to run openvpn + as admin with a nice password prompt. The actual command needs to be + appended. + + :rtype: (str, list) + """ + iconpath = os.path.abspath(os.path.join( + os.getcwd(), + "../../../Resources/leap-client.tiff")) + has_icon = os.path.isfile(iconpath) + args = ["--icon=%s" % iconpath] if has_icon else [] + args.append("--prompt=%s" % (self.SUDO_MSG,)) + + return self.COCOASUDO, args + def get_vpn_command(self, eipconfig=None, providerconfig=None, socket_host=None, socket_port="unix"): """ @@ -597,11 +613,8 @@ class DarwinVPNLauncher(VPNLauncher): '--ca', providerconfig.get_ca_cert_path() ] - # We are using osascript until we can write a proper wrapper - # for privilege escalation. - - command = self.OSASCRIPT_BIN - cmd_args = ["-e", self.OSX_ASADMIN % (' '.join(args),)] + command, cargs = self.get_cocoasudo_cmd() + cmd_args = cargs + args logger.debug("Running VPN with command:") logger.debug("%s %s" % (command, " ".join(cmd_args))) |