From 6e197c1353c788109df07ee6d1242a5c2327e8f9 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 1 Aug 2012 09:58:08 +0900 Subject: fileutil.which implementation --- src/leap/util/__init__.py | 0 src/leap/util/coroutines.py | 107 +++++++++++++++++++++++++++++++++++++++++ src/leap/util/fileutil.py | 73 ++++++++++++++++++++++++++++ src/leap/util/leap_argparse.py | 20 ++++++++ 4 files changed, 200 insertions(+) create mode 100644 src/leap/util/__init__.py create mode 100644 src/leap/util/coroutines.py create mode 100644 src/leap/util/fileutil.py create mode 100644 src/leap/util/leap_argparse.py (limited to 'src/leap/util') diff --git a/src/leap/util/__init__.py b/src/leap/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/leap/util/coroutines.py b/src/leap/util/coroutines.py new file mode 100644 index 00000000..5e25eb63 --- /dev/null +++ b/src/leap/util/coroutines.py @@ -0,0 +1,107 @@ +# the problem of watching a stdout pipe from +# openvpn binary: using subprocess and coroutines +# acting as event consumers + +from __future__ import division, print_function + +from subprocess import PIPE, Popen +import sys +from threading import Thread + +ON_POSIX = 'posix' in sys.builtin_module_names + + +# +# Coroutines goodies +# + +def coroutine(func): + def start(*args, **kwargs): + cr = func(*args, **kwargs) + cr.next() + return cr + return start + + +@coroutine +def process_events(callback): + """ + coroutine loop that receives + events sent and dispatch the callback. + :param callback: callback to be called\ +for each event + :type callback: callable + """ + try: + while True: + m = (yield) + if callable(callback): + callback(m) + else: + #XXX log instead + print('not a callable passed') + except GeneratorExit: + return + +# +# Threads +# + + +def launch_thread(target, args): + """ + launch and demonize thread. + :param target: target function that will run in thread + :type target: function + :param args: args to be passed to thread + :type args: list + """ + t = Thread(target=target, + args=args) + t.daemon = True + t.start() + return t + + +def watch_output(out, observers): + """ + initializes dict of observer coroutines + and pushes lines to each of them as they are received + from the watched output. + :param out: stdout of a process. + :type out: fd + :param observers: tuple of coroutines to send data\ +for each event + :type ovservers: tuple + """ + observer_dict = {observer: process_events(observer) + for observer in observers} + for line in iter(out.readline, b''): + for obs in observer_dict: + observer_dict[obs].send(line) + out.close() + + +def spawn_and_watch_process(command, args, observers=None): + """ + spawns a subprocess with command, args, and launch + a watcher thread. + :param command: command to be executed in the subprocess + :type command: str + :param args: arguments + :type args: list + :param observers: tuple of observer functions to be called \ +for each line in the subprocess output. + :type observers: tuple + :return: a tuple containing the child process instance, and watcher_thread, + :rtype: (Subprocess, Thread) + """ + subp = Popen([command] + args, + stdout=PIPE, + stderr=PIPE, + bufsize=1, + close_fds=ON_POSIX) + watcher = launch_thread( + watch_output, + (subp.stdout, observers)) + return subp, watcher diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py new file mode 100644 index 00000000..86a44a89 --- /dev/null +++ b/src/leap/util/fileutil.py @@ -0,0 +1,73 @@ +from itertools import chain +import os +import platform +import stat + + +def is_user_executable(fpath): + st = os.stat(fpath) + return bool(st.st_mode & stat.S_IXUSR) + + +def extend_path(): + ourplatform = platform.system() + if ourplatform == "Linux": + return "/usr/local/sbin:/usr/sbin" + # XXX add mac / win extended search paths? + + +def which(program): + """ + an implementation of which + that extends the path with + other locations, like sbin + (f.i., openvpn binary is likely to be there) + @param program: a string representing the binary we're looking for. + """ + def is_exe(fpath): + """ + check that path exists, + it's a file, + and is executable by the owner + """ + # we would check for access, + # but it's likely that we're + # using uid 0 + polkitd + + return os.path.isfile(fpath)\ + and is_user_executable(fpath) + + def ext_candidates(fpath): + yield fpath + for ext in os.environ.get("PATHEXT", "").split(os.pathsep): + yield fpath + ext + + def iter_path(pathset): + """ + returns iterator with + full path for a given path list + and the current target bin. + """ + for path in pathset.split(os.pathsep): + exe_file = os.path.join(path, program) + #print 'file=%s' % exe_file + for candidate in ext_candidates(exe_file): + if is_exe(candidate): + yield candidate + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + # extended iterator + # with extra path + extended_path = chain( + iter_path(os.environ["PATH"]), + iter_path(extend_path())) + for candidate in extended_path: + if candidate is not None: + return candidate + + # sorry bro. + return None diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py new file mode 100644 index 00000000..9c355134 --- /dev/null +++ b/src/leap/util/leap_argparse.py @@ -0,0 +1,20 @@ +import argparse + + +def build_parser(): + epilog = "Copyright 2012 The Leap Project" + parser = argparse.ArgumentParser(description=""" +Launches main LEAP Client""", epilog=epilog) + parser.add_argument('--debug', action="store_true", + help='launches in debug mode') + parser.add_argument('--config', metavar="CONFIG FILE", nargs='?', + action="store", dest="config_file", + type=argparse.FileType('r'), + help='optional config file') + return parser + + +def init_leapc_args(): + parser = build_parser() + opts = parser.parse_args() + return parser, opts -- cgit v1.2.3 From 23502b72f8cd8a9ec2fd28387f7788aeef54c2d1 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 2 Aug 2012 02:21:45 +0900 Subject: create config file if not exist. also locate openvpn binary when building eip configparser defaults. implement half of feature #356 --- src/leap/util/fileutil.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/leap/util') diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index 86a44a89..bb2c243b 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -1,3 +1,4 @@ +import errno from itertools import chain import os import platform @@ -71,3 +72,16 @@ def which(program): # sorry bro. return None + + +def mkdir_p(path): + """ + implements mkdir -p functionality + """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST: + pass + else: + raise -- cgit v1.2.3 From 530e10214a6f018909714b288d997df13ab4f9df Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 8 Aug 2012 06:53:10 +0900 Subject: check for bad permissions on vpn key files --- src/leap/util/fileutil.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/leap/util') diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index bb2c243b..cc3bf34b 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -1,10 +1,14 @@ import errno from itertools import chain +import logging import os import platform import stat +logger = logging.getLogger() + + def is_user_executable(fpath): st = os.stat(fpath) return bool(st.st_mode & stat.S_IXUSR) @@ -85,3 +89,23 @@ def mkdir_p(path): pass else: raise + + +def check_and_fix_urw_only(_file): + """ + test for 600 mode and try + to set it if anything different found + """ + mode = os.stat(_file).st_mode + if mode != int('600', 8): + try: + logger.warning( + 'bad permission on %s ' + 'attempting to set 600', + _file) + os.chmod(_file, stat.S_IRUSR | stat.S_IWUSR) + except OSError: + logger.error( + 'error while trying to chmod 600 %s', + _file) + raise -- cgit v1.2.3 From d769925c9819c012602595cc0f47c8a81444ca0e Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 8 Aug 2012 19:29:14 +0900 Subject: bunch of tests for leap/util/fileutil --- src/leap/util/test_fileutil.py | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/leap/util/test_fileutil.py (limited to 'src/leap/util') diff --git a/src/leap/util/test_fileutil.py b/src/leap/util/test_fileutil.py new file mode 100644 index 00000000..849decaf --- /dev/null +++ b/src/leap/util/test_fileutil.py @@ -0,0 +1,99 @@ +import os +import platform +import shutil +import stat +import tempfile +import unittest + +from leap.util import fileutil + + +class FileUtilTest(unittest.TestCase): + """ + test our file utils + """ + + def setUp(self): + self.system = platform.system() + self.create_temp_dir() + + def tearDown(self): + self.remove_temp_dir() + + # + # helpers + # + + def create_temp_dir(self): + self.tmpdir = tempfile.mkdtemp() + + def remove_temp_dir(self): + shutil.rmtree(self.tmpdir) + + def get_file_path(self, filename): + return os.path.join( + self.tmpdir, + filename) + + def touch_exec_file(self): + fp = self.get_file_path('testexec') + open(fp, 'w').close() + os.chmod( + fp, + stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) + return fp + + def get_mode(self, fp): + return stat.S_IMODE(os.stat(fp).st_mode) + + # + # tests + # + + def test_is_user_executable(self): + """ + test that a 700 file + is an 700 file. kindda oximoronic, but... + """ + # XXX could check access X_OK + + fp = self.touch_exec_file() + mode = self.get_mode(fp) + self.assertEqual(mode, int('700', 8)) + + def test_which(self): + """ + not a very reliable test, + but I cannot think of anything smarter now + I guess it's highly improbable that copy + command is somewhere else..? + """ + # XXX yep, we can change the syspath + # for the test... ! + + if self.system == "Linux": + self.assertEqual( + fileutil.which('cp'), + '/bin/cp') + + def test_mkdir_p(self): + """ + test our mkdir -p implementation + """ + testdir = self.get_file_path( + os.path.join('test', 'foo', 'bar')) + self.assertEqual(os.path.isdir(testdir), False) + fileutil.mkdir_p(testdir) + self.assertEqual(os.path.isdir(testdir), True) + + def test_check_and_fix_urw_only(self): + """ + test function that fixes perms on + files that should be rw only for owner + """ + fp = self.touch_exec_file() + mode = self.get_mode(fp) + self.assertEqual(mode, int('700', 8)) + fileutil.check_and_fix_urw_only(fp) + mode = self.get_mode(fp) + self.assertEqual(mode, int('600', 8)) -- cgit v1.2.3 From e8c950c65ebd5bb4ba0dcbfac869e7b40b902b8c Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 8 Aug 2012 19:29:56 +0900 Subject: fix bad permission check on check_and_fix_urw_only (was not testing the mode properly. gotcha!) --- src/leap/util/fileutil.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index cc3bf34b..429e4b12 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -96,7 +96,9 @@ def check_and_fix_urw_only(_file): test for 600 mode and try to set it if anything different found """ - mode = os.stat(_file).st_mode + mode = stat.S_IMODE( + os.stat(_file).st_mode) + if mode != int('600', 8): try: logger.warning( -- cgit v1.2.3 From 0ac0cbb9f6dd91a414747f2a59d5a9d1bbfee571 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 8 Aug 2012 19:36:17 +0900 Subject: stub test for leap_argparse --- src/leap/util/test_leap_argparse.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/leap/util/test_leap_argparse.py (limited to 'src/leap/util') diff --git a/src/leap/util/test_leap_argparse.py b/src/leap/util/test_leap_argparse.py new file mode 100644 index 00000000..1442e827 --- /dev/null +++ b/src/leap/util/test_leap_argparse.py @@ -0,0 +1,27 @@ +from argparse import Namespace +import unittest + +from leap.util import leap_argparse + + +class LeapArgParseTest(unittest.TestCase): + """ + Test argparse options for eip client + """ + + def setUp(self): + """ + get the parser + """ + self.parser = leap_argparse.build_parser() + + def test_debug_mode(self): + """ + test debug mode option + """ + opts = self.parser.parse_args( + ['--debug']) + self.assertEqual( + opts, + Namespace(config_file=None, + debug=True)) -- cgit v1.2.3 From 04cf64af3702ab85a670efe6850c60f20bbf7eb0 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 22 Aug 2012 04:11:44 +0900 Subject: conductor tests --- src/leap/util/test_fileutil.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/test_fileutil.py b/src/leap/util/test_fileutil.py index 849decaf..f5dbe108 100644 --- a/src/leap/util/test_fileutil.py +++ b/src/leap/util/test_fileutil.py @@ -52,8 +52,7 @@ class FileUtilTest(unittest.TestCase): def test_is_user_executable(self): """ - test that a 700 file - is an 700 file. kindda oximoronic, but... + touch_exec_file creates in mode 700? """ # XXX could check access X_OK @@ -63,10 +62,10 @@ class FileUtilTest(unittest.TestCase): def test_which(self): """ + which implementation ok? not a very reliable test, but I cannot think of anything smarter now I guess it's highly improbable that copy - command is somewhere else..? """ # XXX yep, we can change the syspath # for the test... ! @@ -78,7 +77,7 @@ class FileUtilTest(unittest.TestCase): def test_mkdir_p(self): """ - test our mkdir -p implementation + our own mkdir -p implementation ok? """ testdir = self.get_file_path( os.path.join('test', 'foo', 'bar')) @@ -88,8 +87,7 @@ class FileUtilTest(unittest.TestCase): def test_check_and_fix_urw_only(self): """ - test function that fixes perms on - files that should be rw only for owner + ensure check_and_fix_urx_only ok? """ fp = self.touch_exec_file() mode = self.get_mode(fp) -- cgit v1.2.3 From 38e6c9c6345ca28ed0134ce6f4d43ec650103709 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 22 Aug 2012 04:57:38 +0900 Subject: mv util tests to folder --- src/leap/util/test_fileutil.py | 97 ----------------------------- src/leap/util/test_leap_argparse.py | 27 -------- src/leap/util/tests/test_fileutil.py | 100 ++++++++++++++++++++++++++++++ src/leap/util/tests/test_leap_argparse.py | 30 +++++++++ 4 files changed, 130 insertions(+), 124 deletions(-) delete mode 100644 src/leap/util/test_fileutil.py delete mode 100644 src/leap/util/test_leap_argparse.py create mode 100644 src/leap/util/tests/test_fileutil.py create mode 100644 src/leap/util/tests/test_leap_argparse.py (limited to 'src/leap/util') diff --git a/src/leap/util/test_fileutil.py b/src/leap/util/test_fileutil.py deleted file mode 100644 index f5dbe108..00000000 --- a/src/leap/util/test_fileutil.py +++ /dev/null @@ -1,97 +0,0 @@ -import os -import platform -import shutil -import stat -import tempfile -import unittest - -from leap.util import fileutil - - -class FileUtilTest(unittest.TestCase): - """ - test our file utils - """ - - def setUp(self): - self.system = platform.system() - self.create_temp_dir() - - def tearDown(self): - self.remove_temp_dir() - - # - # helpers - # - - def create_temp_dir(self): - self.tmpdir = tempfile.mkdtemp() - - def remove_temp_dir(self): - shutil.rmtree(self.tmpdir) - - def get_file_path(self, filename): - return os.path.join( - self.tmpdir, - filename) - - def touch_exec_file(self): - fp = self.get_file_path('testexec') - open(fp, 'w').close() - os.chmod( - fp, - stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) - return fp - - def get_mode(self, fp): - return stat.S_IMODE(os.stat(fp).st_mode) - - # - # tests - # - - def test_is_user_executable(self): - """ - touch_exec_file creates in mode 700? - """ - # XXX could check access X_OK - - fp = self.touch_exec_file() - mode = self.get_mode(fp) - self.assertEqual(mode, int('700', 8)) - - def test_which(self): - """ - which implementation ok? - not a very reliable test, - but I cannot think of anything smarter now - I guess it's highly improbable that copy - """ - # XXX yep, we can change the syspath - # for the test... ! - - if self.system == "Linux": - self.assertEqual( - fileutil.which('cp'), - '/bin/cp') - - def test_mkdir_p(self): - """ - our own mkdir -p implementation ok? - """ - testdir = self.get_file_path( - os.path.join('test', 'foo', 'bar')) - self.assertEqual(os.path.isdir(testdir), False) - fileutil.mkdir_p(testdir) - self.assertEqual(os.path.isdir(testdir), True) - - def test_check_and_fix_urw_only(self): - """ - ensure check_and_fix_urx_only ok? - """ - fp = self.touch_exec_file() - mode = self.get_mode(fp) - self.assertEqual(mode, int('700', 8)) - fileutil.check_and_fix_urw_only(fp) - mode = self.get_mode(fp) - self.assertEqual(mode, int('600', 8)) diff --git a/src/leap/util/test_leap_argparse.py b/src/leap/util/test_leap_argparse.py deleted file mode 100644 index 1442e827..00000000 --- a/src/leap/util/test_leap_argparse.py +++ /dev/null @@ -1,27 +0,0 @@ -from argparse import Namespace -import unittest - -from leap.util import leap_argparse - - -class LeapArgParseTest(unittest.TestCase): - """ - Test argparse options for eip client - """ - - def setUp(self): - """ - get the parser - """ - self.parser = leap_argparse.build_parser() - - def test_debug_mode(self): - """ - test debug mode option - """ - opts = self.parser.parse_args( - ['--debug']) - self.assertEqual( - opts, - Namespace(config_file=None, - debug=True)) diff --git a/src/leap/util/tests/test_fileutil.py b/src/leap/util/tests/test_fileutil.py new file mode 100644 index 00000000..f5131b3d --- /dev/null +++ b/src/leap/util/tests/test_fileutil.py @@ -0,0 +1,100 @@ +import os +import platform +import shutil +import stat +import tempfile +import unittest + +from leap.util import fileutil + + +class FileUtilTest(unittest.TestCase): + """ + test our file utils + """ + + def setUp(self): + self.system = platform.system() + self.create_temp_dir() + + def tearDown(self): + self.remove_temp_dir() + + # + # helpers + # + + def create_temp_dir(self): + self.tmpdir = tempfile.mkdtemp() + + def remove_temp_dir(self): + shutil.rmtree(self.tmpdir) + + def get_file_path(self, filename): + return os.path.join( + self.tmpdir, + filename) + + def touch_exec_file(self): + fp = self.get_file_path('testexec') + open(fp, 'w').close() + os.chmod( + fp, + stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) + return fp + + def get_mode(self, fp): + return stat.S_IMODE(os.stat(fp).st_mode) + + # + # tests + # + + def test_is_user_executable(self): + """ + touch_exec_file creates in mode 700? + """ + # XXX could check access X_OK + + fp = self.touch_exec_file() + mode = self.get_mode(fp) + self.assertEqual(mode, int('700', 8)) + + def test_which(self): + """ + which implementation ok? + not a very reliable test, + but I cannot think of anything smarter now + I guess it's highly improbable that copy + """ + # XXX yep, we can change the syspath + # for the test... ! + + if self.system == "Linux": + self.assertEqual( + fileutil.which('cp'), + '/bin/cp') + + def test_mkdir_p(self): + """ + our own mkdir -p implementation ok? + """ + testdir = self.get_file_path( + os.path.join('test', 'foo', 'bar')) + self.assertEqual(os.path.isdir(testdir), False) + fileutil.mkdir_p(testdir) + self.assertEqual(os.path.isdir(testdir), True) + + def test_check_and_fix_urw_only(self): + """ + ensure check_and_fix_urx_only ok? + """ + fp = self.touch_exec_file() + mode = self.get_mode(fp) + self.assertEqual(mode, int('700', 8)) + fileutil.check_and_fix_urw_only(fp) + mode = self.get_mode(fp) + self.assertEqual(mode, int('600', 8)) + +if __name__ == "__main__": + unittest.main() diff --git a/src/leap/util/tests/test_leap_argparse.py b/src/leap/util/tests/test_leap_argparse.py new file mode 100644 index 00000000..f4c86e36 --- /dev/null +++ b/src/leap/util/tests/test_leap_argparse.py @@ -0,0 +1,30 @@ +from argparse import Namespace +import unittest + +from leap.util import leap_argparse + + +class LeapArgParseTest(unittest.TestCase): + """ + Test argparse options for eip client + """ + + def setUp(self): + """ + get the parser + """ + self.parser = leap_argparse.build_parser() + + def test_debug_mode(self): + """ + test debug mode option + """ + opts = self.parser.parse_args( + ['--debug']) + self.assertEqual( + opts, + Namespace(config_file=None, + debug=True)) + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3 From 6c4012fc128c5af1b75cf33eef00590cf0e82438 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 31 Aug 2012 04:39:13 +0900 Subject: deprecated configparser. closes #500 --- src/leap/util/fileutil.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index 429e4b12..aef4cfe0 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -21,7 +21,7 @@ def extend_path(): # XXX add mac / win extended search paths? -def which(program): +def which(program, path=None): """ an implementation of which that extends the path with @@ -67,8 +67,10 @@ def which(program): else: # extended iterator # with extra path + if path is None: + path = os.environ['PATH'] extended_path = chain( - iter_path(os.environ["PATH"]), + iter_path(path), iter_path(extend_path())) for candidate in extended_path: if candidate is not None: -- cgit v1.2.3 From 813a97957572aad97d50319db96b55a74b8ed307 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 5 Sep 2012 07:54:10 +0900 Subject: can log to logfile app.py --debug --logfile /tmp/foo.log --- src/leap/util/leap_argparse.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/leap/util') diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py index 9c355134..f329cf3e 100644 --- a/src/leap/util/leap_argparse.py +++ b/src/leap/util/leap_argparse.py @@ -11,6 +11,10 @@ Launches main LEAP Client""", epilog=epilog) action="store", dest="config_file", type=argparse.FileType('r'), help='optional config file') + parser.add_argument('--logfile', metavar="LOG FILE", nargs='?', + action="store", dest="log_file", + #type=argparse.FileType('w'), + help='optional log file') return parser -- cgit v1.2.3 From 4e207f6c11eed349fa71ba9f3a9fec903131cf8e Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 6 Sep 2012 03:14:05 +0900 Subject: fix argparse test --- src/leap/util/tests/test_leap_argparse.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/tests/test_leap_argparse.py b/src/leap/util/tests/test_leap_argparse.py index f4c86e36..8a275f89 100644 --- a/src/leap/util/tests/test_leap_argparse.py +++ b/src/leap/util/tests/test_leap_argparse.py @@ -23,8 +23,10 @@ class LeapArgParseTest(unittest.TestCase): ['--debug']) self.assertEqual( opts, - Namespace(config_file=None, - debug=True)) + Namespace( + config_file=None, + debug=True, + log_file=None)) if __name__ == "__main__": unittest.main() -- cgit v1.2.3 From 99058b9f6536a3717ab82a9d77b09d5489334eb5 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 12 Sep 2012 10:32:22 +0900 Subject: add openvpn-verb option to cli. Closes #534. accepts int [1-6] that get passed to openvpn invocation. We should filter out the polling "state"/"status" commands from the log if we want it to be real useful. --- src/leap/util/leap_argparse.py | 4 ++++ src/leap/util/tests/test_leap_argparse.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py index f329cf3e..3b38aa77 100644 --- a/src/leap/util/leap_argparse.py +++ b/src/leap/util/leap_argparse.py @@ -15,6 +15,10 @@ Launches main LEAP Client""", epilog=epilog) action="store", dest="log_file", #type=argparse.FileType('w'), help='optional log file') + parser.add_argument('--openvpn-verbosity', nargs='?', + type=int, + action="store", dest="openvpn_verb", + help='verbosity level for openvpn logs [1-6]') return parser diff --git a/src/leap/util/tests/test_leap_argparse.py b/src/leap/util/tests/test_leap_argparse.py index 8a275f89..173c87bb 100644 --- a/src/leap/util/tests/test_leap_argparse.py +++ b/src/leap/util/tests/test_leap_argparse.py @@ -26,7 +26,8 @@ class LeapArgParseTest(unittest.TestCase): Namespace( config_file=None, debug=True, - log_file=None)) + log_file=None, + openvpn_verb=None)) if __name__ == "__main__": unittest.main() -- cgit v1.2.3 From d1ebe98239fbc2baffa345558d396fa539e79202 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 21 Sep 2012 06:32:40 +0900 Subject: added --no-provider-checks and --no-ca-verify for ease of debugging Close #604 --- src/leap/util/leap_argparse.py | 17 +++++++++++++++-- src/leap/util/tests/test_leap_argparse.py | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py index 3b38aa77..2f996a31 100644 --- a/src/leap/util/leap_argparse.py +++ b/src/leap/util/leap_argparse.py @@ -2,12 +2,16 @@ import argparse def build_parser(): + """ + all the options for the leap arg parser + Some of these could be switched on only if debug flag is present! + """ epilog = "Copyright 2012 The Leap Project" parser = argparse.ArgumentParser(description=""" Launches main LEAP Client""", epilog=epilog) - parser.add_argument('--debug', action="store_true", + parser.add_argument('-d', '--debug', action="store_true", help='launches in debug mode') - parser.add_argument('--config', metavar="CONFIG FILE", nargs='?', + parser.add_argument('-c', '--config', metavar="CONFIG FILE", nargs='?', action="store", dest="config_file", type=argparse.FileType('r'), help='optional config file') @@ -19,6 +23,15 @@ Launches main LEAP Client""", epilog=epilog) type=int, action="store", dest="openvpn_verb", help='verbosity level for openvpn logs [1-6]') + parser.add_argument('-l', '--no-provider-checks', + action="store_true", default=False, + help="skips download of provider config files. gets " + "config from local files only. Will fail if cannot " + "find any") + parser.add_argument('-k', '--no-ca-verify', + action="store_true", default=False, + help="(insecure). Skips verification of the server " + "certificate used in TLS handshake.") return parser diff --git a/src/leap/util/tests/test_leap_argparse.py b/src/leap/util/tests/test_leap_argparse.py index 173c87bb..082919b7 100644 --- a/src/leap/util/tests/test_leap_argparse.py +++ b/src/leap/util/tests/test_leap_argparse.py @@ -27,6 +27,8 @@ class LeapArgParseTest(unittest.TestCase): config_file=None, debug=True, log_file=None, + no_provider_checks=False, + no_ca_verify=False, openvpn_verb=None)) if __name__ == "__main__": -- cgit v1.2.3 From 021e7ea900c64af9577412f11349f69e01634c0c Mon Sep 17 00:00:00 2001 From: antialias Date: Tue, 25 Sep 2012 15:48:40 -0400 Subject: fixed typo. --- src/leap/util/coroutines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/coroutines.py b/src/leap/util/coroutines.py index e7ccfacf..b9d0a98b 100644 --- a/src/leap/util/coroutines.py +++ b/src/leap/util/coroutines.py @@ -72,7 +72,7 @@ def watch_output(out, observers): :type out: fd :param observers: tuple of coroutines to send data\ for each event - :type ovservers: tuple + :type observers: tuple """ observer_dict = dict(((observer, process_events(observer)) for observer in observers)) -- cgit v1.2.3 From 6728eb9afb21bad867e4052a6190a9bdb34c928a Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 8 Oct 2012 07:50:24 +0900 Subject: popup dialog error when network error happens we are shutting down for now. we should be acting upon failures in the near future. lowered the recurrent checks interval to 10 seconds. --- src/leap/util/coroutines.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/coroutines.py b/src/leap/util/coroutines.py index b9d0a98b..0657fc04 100644 --- a/src/leap/util/coroutines.py +++ b/src/leap/util/coroutines.py @@ -4,10 +4,13 @@ from __future__ import division, print_function +import logging from subprocess import PIPE, Popen import sys from threading import Thread +logger = logging.getLogger(__name__) + ON_POSIX = 'posix' in sys.builtin_module_names @@ -38,8 +41,7 @@ for each event if callable(callback): callback(m) else: - #XXX log instead - print('not a callable passed') + logger.debug('not a callable passed') except GeneratorExit: return -- cgit v1.2.3 From f751247efd8b941989b4f72397bda03e66dee7c0 Mon Sep 17 00:00:00 2001 From: antialias Date: Mon, 8 Oct 2012 16:15:30 -0400 Subject: added openvpn to debian install line added python-coverage to testing install line rewrote PyQt installation instructions fixed pkg/test-requirements lines fixed nosetest example (#740) --- src/leap/util/tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/leap/util/tests/__init__.py (limited to 'src/leap/util') diff --git a/src/leap/util/tests/__init__.py b/src/leap/util/tests/__init__.py new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From c7eaaf710d0963396bd1658bebe7fc36a0deb80b Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 17 Oct 2012 05:35:43 +0900 Subject: added skeleton for generic client wizard flow --- src/leap/util/dicts.py | 258 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 src/leap/util/dicts.py (limited to 'src/leap/util') diff --git a/src/leap/util/dicts.py b/src/leap/util/dicts.py new file mode 100644 index 00000000..d8177973 --- /dev/null +++ b/src/leap/util/dicts.py @@ -0,0 +1,258 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. + +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) -- cgit v1.2.3 From 8118056a244ca74d16380ad26a70e3da40e7e401 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 9 Nov 2012 11:21:40 +0900 Subject: connect page merged into regvalidation. Flow nearly working with fake provider, except for authentication. --- src/leap/util/web.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/leap/util/web.py (limited to 'src/leap/util') diff --git a/src/leap/util/web.py b/src/leap/util/web.py new file mode 100644 index 00000000..6ddf4b21 --- /dev/null +++ b/src/leap/util/web.py @@ -0,0 +1,18 @@ +""" +web related utilities +""" + + +def get_https_domain_and_port(full_domain): + """ + returns a tuple with domain and port + from a full_domain string that can + contain a colon + """ + domain_split = full_domain.split(':') + _len = len(domain_split) + if _len == 1: + domain, port = full_domain, 443 + if _len == 2: + domain, port = domain_split + return domain, port -- cgit v1.2.3 From 8fd77ba036cb78c81939bbfce312b12cdc90d881 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 9 Nov 2012 18:13:32 +0900 Subject: working version of the fake provider. wizard can now be completely tested against this. --- src/leap/util/web.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/web.py b/src/leap/util/web.py index 6ddf4b21..b2aef058 100644 --- a/src/leap/util/web.py +++ b/src/leap/util/web.py @@ -3,16 +3,37 @@ web related utilities """ +class UsageError(Exception): + """ """ + + def get_https_domain_and_port(full_domain): """ returns a tuple with domain and port from a full_domain string that can contain a colon """ + if full_domain is None: + return None, None + + https_sch = "https://" + http_sch = "http://" + + if full_domain.startswith(https_sch): + full_domain = full_domain.lstrip(https_sch) + elif full_domain.startswith(http_sch): + raise UsageError( + "cannot be called with a domain " + "that begins with 'http://'") + domain_split = full_domain.split(':') _len = len(domain_split) if _len == 1: domain, port = full_domain, 443 - if _len == 2: + elif _len == 2: domain, port = domain_split + else: + raise UsageError( + "must be called with one only parameter" + "in the form domain[:port]") return domain, port -- cgit v1.2.3 From d24c7328fa845737dbb83d512e4b3f287634c4cc Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 14 Nov 2012 00:33:05 +0900 Subject: make tests pass + pep8 They were breaking mainly because I did not bother to have a pass over them to change the PROVIDER settings from the branding case. All good now, although much testing is yet needed and some refactor could be used. long live green tests! --- src/leap/util/dicts.py | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/dicts.py b/src/leap/util/dicts.py index d8177973..001ca96b 100644 --- a/src/leap/util/dicts.py +++ b/src/leap/util/dicts.py @@ -1,4 +1,5 @@ -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Backport of OrderedDict() class that runs +# on Python 2.4, 2.5, 2.6, 2.7 and pypy. # Passes Python2.7's test suite and incorporates all the latest updates. try: @@ -17,9 +18,11 @@ class OrderedDict(dict): # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. + # Big-O running times for all methods are the same as for regular + # dictionaries. - # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The internal self.__map dictionary maps keys to links in a doubly + # linked list. # The circular doubly linked list starts and ends with a sentinel element. # The sentinel element never gets deleted (this simplifies the algorithm). # Each link is stored as a list of length three: [PREV, NEXT, KEY]. @@ -42,8 +45,9 @@ class OrderedDict(dict): def __setitem__(self, key, value, dict_setitem=dict.__setitem__): 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. + # Setting a new item creates a new link which goes at the end + # of the linked list, and the inherited dictionary is updated + # with the new key/value pair. if key not in self: root = self.__root last = root[0] @@ -53,7 +57,8 @@ class OrderedDict(dict): def __delitem__(self, key, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. + # then removed by updating the links in the predecessor and successor + # nodes. dict_delitem(self, key) link_prev, link_next, key = self.__map.pop(key) link_prev[1] = link_next @@ -89,8 +94,8 @@ class OrderedDict(dict): def popitem(self, last=True): '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - + Pairs are returned in LIFO order if last is true or FIFO order if + false. ''' if not self: raise KeyError('dictionary is empty') @@ -142,11 +147,13 @@ class OrderedDict(dict): '''od.update(E, **F) -> None. Update od from dict/iterable E and F. If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): + od[k] = E[k] Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - + In either case, this is followed by: for k, v in F.items(): + od[k] = v ''' + if len(args) > 2: raise TypeError('update() takes at most 2 positional ' 'arguments (%d given)' % (len(args),)) @@ -169,13 +176,16 @@ class OrderedDict(dict): for key, value in kwds.items(): self[key] = value - __update = update # let subclasses override update without breaking __init__ + __update = update # let subclasses override update + # without breaking __init__ __marker = object() def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. + '''od.pop(k[,d]) -> v + remove specified key and return the corresponding value. + If key is not found, d is returned if given, + otherwise KeyError is raised. ''' if key in self: @@ -232,12 +242,12 @@ class OrderedDict(dict): return d def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + '''od.__eq__(y) <==> od==y. + Comparison to another OD is order-sensitive while comparison to a regular mapping is order-insensitive. - ''' if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() + return len(self) == len(other) and self.items() == other.items() return dict.__eq__(self, other) def __ne__(self, other): -- cgit v1.2.3 From 53fa2c134ab2c96376276aa1c0ed74db0aaba218 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 10 Dec 2012 23:20:09 +0900 Subject: get cipher config from eip-service --- src/leap/util/misc.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/leap/util/misc.py (limited to 'src/leap/util') diff --git a/src/leap/util/misc.py b/src/leap/util/misc.py new file mode 100644 index 00000000..3c26892b --- /dev/null +++ b/src/leap/util/misc.py @@ -0,0 +1,16 @@ +""" +misc utils +""" + + +class ImproperlyConfigured(Exception): + """ + """ + + +def null_check(value, value_name): + try: + assert value is not None + except AssertionError: + raise ImproperlyConfigured( + "%s parameter cannot be None" % value_name) -- cgit v1.2.3 From 04d423e2a89034dfb86fe305108162fd2a696079 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 12 Dec 2012 03:29:31 +0900 Subject: tests for openvpn options and make the rest of tests pass after some changes in this branch (dirtyness in config files) --- src/leap/util/fileutil.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/leap/util') diff --git a/src/leap/util/fileutil.py b/src/leap/util/fileutil.py index aef4cfe0..820ffe46 100644 --- a/src/leap/util/fileutil.py +++ b/src/leap/util/fileutil.py @@ -93,6 +93,11 @@ def mkdir_p(path): raise +def mkdir_f(path): + folder, fname = os.path.split(path) + mkdir_p(folder) + + def check_and_fix_urw_only(_file): """ test for 600 mode and try -- cgit v1.2.3 From 490cde9c33039c2c5b16d929d6f8bb8e8f06f430 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 5 Dec 2012 23:50:08 +0900 Subject: tests for firstrun/wizard --- src/leap/util/web.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src/leap/util') diff --git a/src/leap/util/web.py b/src/leap/util/web.py index b2aef058..15de0561 100644 --- a/src/leap/util/web.py +++ b/src/leap/util/web.py @@ -13,6 +13,7 @@ def get_https_domain_and_port(full_domain): from a full_domain string that can contain a colon """ + full_domain = unicode(full_domain) if full_domain is None: return None, None -- cgit v1.2.3 From b0c3c9194447f20306111a31ee5a6d4828fed158 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 21 Dec 2012 07:43:16 +0900 Subject: readme typos, updated translation docs --- src/leap/util/translations.py | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/leap/util/translations.py (limited to 'src/leap/util') diff --git a/src/leap/util/translations.py b/src/leap/util/translations.py new file mode 100644 index 00000000..c06aa947 --- /dev/null +++ b/src/leap/util/translations.py @@ -0,0 +1,58 @@ +import inspect + +from PyQt4.QtCore import QCoreApplication + +""" +here I could not do all that I wanted. +the context is not getting passed to the xml file. +Looks like pylupdate4 is somehow a hack that does not +parse too well the python ast. +I guess we could generate the xml for ourselves as a last recourse. +""" + +# XXX BIG NOTE: +# RESIST the temptation to get the translate function +# more compact, or have the Context argument passed as a variable +# It HAS to be explicit due to how the pylupdate parser +# works. + + +qtTranslate = QCoreApplication.translate + + +class LEAPTr: + pass + + +def translate(*args): + """ + translate(Context, text, comment) + """ + print 'translating...' + klsname = None + try: + # get class value from instance + # using live object inspection + prev_frame = inspect.stack()[1][0] + self = inspect.getargvalues(prev_frame).locals.get('self') + if self: + # XXX will this work with QObject wrapper?? + if isinstance(LEAPTr, self) and hasattr(self, 'tr'): + print "we got a self in base class" + return self.tr(*args) + + # Trying to get the class name + # but this is useless, the parser + # has already got the context. + klsname = self.__class__.__name__ + print 'KLSNAME -- ', klsname + except: + print 'error getting stack frame' + + if klsname: + nargs = (klsname,) + args + return qtTranslate(*nargs) + + else: + nargs = ('default', ) + args + return qtTranslate(*nargs) -- cgit v1.2.3 From ec0fc05e3918782dbb29f9f6901c0de22419134d Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 21 Dec 2012 10:28:46 +0900 Subject: magic translatable objects --- src/leap/util/tests/test_translations.py | 22 ++++++++++++++++ src/leap/util/translations.py | 43 +++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/leap/util/tests/test_translations.py (limited to 'src/leap/util') diff --git a/src/leap/util/tests/test_translations.py b/src/leap/util/tests/test_translations.py new file mode 100644 index 00000000..794daeba --- /dev/null +++ b/src/leap/util/tests/test_translations.py @@ -0,0 +1,22 @@ +import unittest + +from leap.util import translations + + +class TrasnlationsTestCase(unittest.TestCase): + """ + tests for translation functions and classes + """ + + def setUp(self): + self.trClass = translations.LEAPTranslatable + + def test_trasnlatable(self): + tr = self.trClass({"en": "house", "es": "casa"}) + eq = self.assertEqual + eq(tr.tr(to="es"), "casa") + eq(tr.tr(to="en"), "house") + + +if __name__ == "__main__": + unittest.main() diff --git a/src/leap/util/translations.py b/src/leap/util/translations.py index c06aa947..14b8c020 100644 --- a/src/leap/util/translations.py +++ b/src/leap/util/translations.py @@ -1,6 +1,10 @@ import inspect +import logging from PyQt4.QtCore import QCoreApplication +from PyQt4.QtCore import QLocale + +logger = logging.getLogger(__name__) """ here I could not do all that I wanted. @@ -20,15 +24,12 @@ I guess we could generate the xml for ourselves as a last recourse. qtTranslate = QCoreApplication.translate -class LEAPTr: - pass - - -def translate(*args): +def translate(*args, **kwargs): """ + our magic function. translate(Context, text, comment) """ - print 'translating...' + #print 'translating...' klsname = None try: # get class value from instance @@ -37,7 +38,7 @@ def translate(*args): self = inspect.getargvalues(prev_frame).locals.get('self') if self: # XXX will this work with QObject wrapper?? - if isinstance(LEAPTr, self) and hasattr(self, 'tr'): + if isinstance(LEAPTranslatable, self) and hasattr(self, 'tr'): print "we got a self in base class" return self.tr(*args) @@ -45,9 +46,10 @@ def translate(*args): # but this is useless, the parser # has already got the context. klsname = self.__class__.__name__ - print 'KLSNAME -- ', klsname + #print 'KLSNAME -- ', klsname except: - print 'error getting stack frame' + logger.error('error getting stack frame') + #print 'error getting stack frame' if klsname: nargs = (klsname,) + args @@ -56,3 +58,26 @@ def translate(*args): else: nargs = ('default', ) + args return qtTranslate(*nargs) + + +class LEAPTranslatable(dict): + """ + An extended dict that implements a .tr method + so it can be translated on the fly by our + magic translate method + """ + + try: + locale = str(QLocale.system().name()).split('_')[0] + except: + logger.warning("could not get system locale!") + print "could not get system locale!" + locale = "en" + + def tr(self, to=None): + if not to: + to = self.locale + _tr = self.get(to, None) + if not _tr: + _tr = self.get("en", None) + return _tr -- cgit v1.2.3 From 4ad663b935fa1845d426dde99a8272942b620e11 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 2 Jan 2013 18:06:13 +0900 Subject: initial OSX packaging --- src/leap/util/leap_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py index 2f996a31..5b0775cc 100644 --- a/src/leap/util/leap_argparse.py +++ b/src/leap/util/leap_argparse.py @@ -37,5 +37,5 @@ Launches main LEAP Client""", epilog=epilog) def init_leapc_args(): parser = build_parser() - opts = parser.parse_args() + opts, unknown = parser.parse_known_args() return parser, opts -- cgit v1.2.3 From 93d5a8cd1ec55c725d5931d86989ea11ac2db844 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 04:20:15 +0900 Subject: fix provider label translation --- src/leap/util/translations.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/translations.py b/src/leap/util/translations.py index 14b8c020..80daa10d 100644 --- a/src/leap/util/translations.py +++ b/src/leap/util/translations.py @@ -17,7 +17,7 @@ I guess we could generate the xml for ourselves as a last recourse. # XXX BIG NOTE: # RESIST the temptation to get the translate function # more compact, or have the Context argument passed as a variable -# It HAS to be explicit due to how the pylupdate parser +# Its name HAS to be explicit due to how the pylupdate parser # works. @@ -29,18 +29,19 @@ def translate(*args, **kwargs): our magic function. translate(Context, text, comment) """ - #print 'translating...' + if len(args) == 1: + obj = args[0] + if isinstance(obj, LEAPTranslatable) and hasattr(obj, 'tr'): + return obj.tr() + klsname = None try: # get class value from instance # using live object inspection prev_frame = inspect.stack()[1][0] - self = inspect.getargvalues(prev_frame).locals.get('self') + locals_ = inspect.getargvalues(prev_frame).locals + self = locals_.get('self') if self: - # XXX will this work with QObject wrapper?? - if isinstance(LEAPTranslatable, self) and hasattr(self, 'tr'): - print "we got a self in base class" - return self.tr(*args) # Trying to get the class name # but this is useless, the parser @@ -49,7 +50,6 @@ def translate(*args, **kwargs): #print 'KLSNAME -- ', klsname except: logger.error('error getting stack frame') - #print 'error getting stack frame' if klsname: nargs = (klsname,) + args -- cgit v1.2.3 From 239a95a65055a5b7128894faf30938496382fbe1 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 05:39:28 +0900 Subject: fix exception i18n --- src/leap/util/translations.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/translations.py b/src/leap/util/translations.py index 80daa10d..d782cfe4 100644 --- a/src/leap/util/translations.py +++ b/src/leap/util/translations.py @@ -51,13 +51,14 @@ def translate(*args, **kwargs): except: logger.error('error getting stack frame') - if klsname: + if klsname and len(args) == 1: nargs = (klsname,) + args return qtTranslate(*nargs) else: - nargs = ('default', ) + args - return qtTranslate(*nargs) + #nargs = ('default', ) + args + #import pdb4qt; pdb4qt.set_trace() + return qtTranslate(*args) class LEAPTranslatable(dict): -- cgit v1.2.3 From ade0eded09176fd687d1ee30724468c048d15065 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 11 Jan 2013 09:16:49 +0900 Subject: fix for missing cacert bundle frozen app cannot find requests cacert bundle. added to Resources to get us going. --- src/leap/util/certs.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/leap/util/certs.py (limited to 'src/leap/util') diff --git a/src/leap/util/certs.py b/src/leap/util/certs.py new file mode 100644 index 00000000..304db08a --- /dev/null +++ b/src/leap/util/certs.py @@ -0,0 +1,17 @@ +import os +import logging + +logger = logging.getLogger(__name__) + + +def get_mac_cabundle(): + # hackaround bundle error + # XXX this needs a better fix! + f = os.path.split(__file__)[0] + sep = os.path.sep + f_ = sep.join(f.split(sep)[:-2]) + verify = os.path.join(f_, 'cacert.pem') + #logger.error('VERIFY PATH = %s' % verify) + exists = os.path.isfile(verify) + #logger.error('do exist? %s', exists) + return verify -- cgit v1.2.3 From d6c8cb0f12e8924820c296a8114a7899f61e5180 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 17 Jan 2013 05:54:16 +0900 Subject: (osx) detect which interface is traffic going thru --- src/leap/util/certs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/certs.py b/src/leap/util/certs.py index 304db08a..f0f790e9 100644 --- a/src/leap/util/certs.py +++ b/src/leap/util/certs.py @@ -14,4 +14,5 @@ def get_mac_cabundle(): #logger.error('VERIFY PATH = %s' % verify) exists = os.path.isfile(verify) #logger.error('do exist? %s', exists) - return verify + if exists: + return verify -- cgit v1.2.3 From 6e9c63f47b98fbfcd3a5104fbfa5cc9d9ffe5143 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 17 Jan 2013 07:31:59 +0900 Subject: osx fixed already running instance check --- src/leap/util/misc.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/leap/util') diff --git a/src/leap/util/misc.py b/src/leap/util/misc.py index 3c26892b..aa3ebe25 100644 --- a/src/leap/util/misc.py +++ b/src/leap/util/misc.py @@ -1,6 +1,9 @@ """ misc utils """ +import psutil + +from leap.base.constants import OPENVPN_BIN class ImproperlyConfigured(Exception): @@ -14,3 +17,20 @@ def null_check(value, value_name): except AssertionError: raise ImproperlyConfigured( "%s parameter cannot be None" % value_name) + +def get_openvpn_pids(): + # binary name might change + + openvpn_pids = [] + for p in psutil.process_iter(): + try: + # XXX Not exact! + # Will give false positives. + # we should check that cmdline BEGINS + # with openvpn or with our wrapper + # (pkexec / osascript / whatever) + if OPENVPN_BIN in ' '.join(p.cmdline): + openvpn_pids.append(p.pid) + except psutil.error.AccessDenied: + pass + return openvpn_pids -- cgit v1.2.3 From 6fb952397573f4bc90f4cd9e72b49fcf6256e95c Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 17 Jan 2013 08:07:45 +0900 Subject: localize exit country if we can only if we can find the geoip database, which comes with geoip-database in debian. we will have to think more about this in the future but it's nice to have now for testing. --- src/leap/util/__init__.py | 9 +++++++++ src/leap/util/geo.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/leap/util/geo.py (limited to 'src/leap/util') diff --git a/src/leap/util/__init__.py b/src/leap/util/__init__.py index e69de29b..a70a9a8b 100644 --- a/src/leap/util/__init__.py +++ b/src/leap/util/__init__.py @@ -0,0 +1,9 @@ +import logging +logger = logging.getLogger(__name__) + +try: + import pygeoip + HAS_GEOIP = True +except ImportError: + logger.debug('PyGeoIP not found. Disabled Geo support.') + HAS_GEOIP = False diff --git a/src/leap/util/geo.py b/src/leap/util/geo.py new file mode 100644 index 00000000..54b29596 --- /dev/null +++ b/src/leap/util/geo.py @@ -0,0 +1,32 @@ +""" +experimental geo support. +not yet a feature. +in debian, we rely on the (optional) geoip-database +""" +import os +import platform + +from leap.util import HAS_GEOIP + +GEOIP = None + +if HAS_GEOIP: + import pygeoip # we know we can :) + + GEOIP_PATH = None + + if platform.system() == "Linux": + PATH = "/usr/share/GeoIP/GeoIP.dat" + if os.path.isfile(PATH): + GEOIP_PATH = PATH + GEOIP = pygeoip.GeoIP(GEOIP_PATH, pygeoip.MEMORY_CACHE) + + +def get_country_name(ip): + if not GEOIP: + return + try: + country = GEOIP.country_name_by_addr(ip) + except pygeoip.GeoIPError: + country = None + return country if country else "-" -- cgit v1.2.3 From ff59da55ef9a176b36cef19d67e7ec363bf5d739 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 24 Jan 2013 02:30:00 +0900 Subject: wizard rephrasing & punctuation --- src/leap/util/translations.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/translations.py b/src/leap/util/translations.py index d782cfe4..f55c8fba 100644 --- a/src/leap/util/translations.py +++ b/src/leap/util/translations.py @@ -56,8 +56,6 @@ def translate(*args, **kwargs): return qtTranslate(*nargs) else: - #nargs = ('default', ) + args - #import pdb4qt; pdb4qt.set_trace() return qtTranslate(*args) -- cgit v1.2.3 From 9cdc193c587631986e579c1ba37a8b982be01238 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 24 Jan 2013 18:47:41 +0900 Subject: all tests green again plus: * added soledad test requirements * removed soledad from run_tests run (+1K tests failing) * added option to run All tests to run_tests script * pep8 cleanup --- src/leap/util/misc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap/util') diff --git a/src/leap/util/misc.py b/src/leap/util/misc.py index aa3ebe25..d869a1ba 100644 --- a/src/leap/util/misc.py +++ b/src/leap/util/misc.py @@ -17,7 +17,8 @@ def null_check(value, value_name): except AssertionError: raise ImproperlyConfigured( "%s parameter cannot be None" % value_name) - + + def get_openvpn_pids(): # binary name might change -- cgit v1.2.3 From 173e532c810d16bcef8f3009bc9203eed9604c87 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 30 Jan 2013 05:26:15 +0900 Subject: comment out unused arguments in the arg parser --- src/leap/util/leap_argparse.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/leap_argparse.py b/src/leap/util/leap_argparse.py index 5b0775cc..3412a72c 100644 --- a/src/leap/util/leap_argparse.py +++ b/src/leap/util/leap_argparse.py @@ -6,16 +6,13 @@ def build_parser(): all the options for the leap arg parser Some of these could be switched on only if debug flag is present! """ - epilog = "Copyright 2012 The Leap Project" + epilog = "Copyright 2012 The LEAP Encryption Access Project" parser = argparse.ArgumentParser(description=""" -Launches main LEAP Client""", epilog=epilog) +Launches the LEAP Client""", epilog=epilog) parser.add_argument('-d', '--debug', action="store_true", - help='launches in debug mode') - parser.add_argument('-c', '--config', metavar="CONFIG FILE", nargs='?', - action="store", dest="config_file", - type=argparse.FileType('r'), - help='optional config file') - parser.add_argument('--logfile', metavar="LOG FILE", nargs='?', + help=("Launches client in debug mode, writing debug" + "info to stdout")) + parser.add_argument('-l', '--logfile', metavar="LOG FILE", nargs='?', action="store", dest="log_file", #type=argparse.FileType('w'), help='optional log file') @@ -23,15 +20,21 @@ Launches main LEAP Client""", epilog=epilog) type=int, action="store", dest="openvpn_verb", help='verbosity level for openvpn logs [1-6]') - parser.add_argument('-l', '--no-provider-checks', - action="store_true", default=False, - help="skips download of provider config files. gets " - "config from local files only. Will fail if cannot " - "find any") - parser.add_argument('-k', '--no-ca-verify', - action="store_true", default=False, - help="(insecure). Skips verification of the server " - "certificate used in TLS handshake.") + + # Not in use, we might want to reintroduce them. + #parser.add_argument('-i', '--no-provider-checks', + #action="store_true", default=False, + #help="skips download of provider config files. gets " + #"config from local files only. Will fail if cannot " + #"find any") + #parser.add_argument('-k', '--no-ca-verify', + #action="store_true", default=False, + #help="(insecure). Skips verification of the server " + #"certificate used in TLS handshake.") + #parser.add_argument('-c', '--config', metavar="CONFIG FILE", nargs='?', + #action="store", dest="config_file", + #type=argparse.FileType('r'), + #help='optional config file') return parser -- cgit v1.2.3 From 6730bb7c76e2273b5b8408cd62f29ce8f7092d29 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 31 Jan 2013 05:39:47 +0900 Subject: fix tests (resources hash + argparse) --- src/leap/util/tests/test_leap_argparse.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/leap/util') diff --git a/src/leap/util/tests/test_leap_argparse.py b/src/leap/util/tests/test_leap_argparse.py index 082919b7..4e2b811f 100644 --- a/src/leap/util/tests/test_leap_argparse.py +++ b/src/leap/util/tests/test_leap_argparse.py @@ -24,11 +24,11 @@ class LeapArgParseTest(unittest.TestCase): self.assertEqual( opts, Namespace( - config_file=None, debug=True, log_file=None, - no_provider_checks=False, - no_ca_verify=False, + #config_file=None, + #no_provider_checks=False, + #no_ca_verify=False, openvpn_verb=None)) if __name__ == "__main__": -- cgit v1.2.3 From 1032e07a50c8bb265ff9bd31b3bb00e83ddb451e Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 13 Feb 2013 01:32:35 +0900 Subject: launch policykit agent if not running --- src/leap/util/polkit.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/leap/util/polkit.py (limited to 'src/leap/util') diff --git a/src/leap/util/polkit.py b/src/leap/util/polkit.py new file mode 100644 index 00000000..70671124 --- /dev/null +++ b/src/leap/util/polkit.py @@ -0,0 +1,26 @@ +import logging + +import sh +from sh import grep +from sh import ps + +logger = logging.getLogger(__name__) + + +def run_polkit_auth_agent(): + logger.debug('launching policykit authentication agent in background...') + polkit = sh.Command('/usr/lib/policykit-1-gnome/' + 'polkit-gnome-authentication-agent-1') + polkit(_bg=True) + + +def check_if_running_polkit_auth(): + """ + check if polkit authentication agent is running + and launch it if it is not + """ + try: + grep(ps('aux'), '[p]olkit-gnome-authentication-agent-1') + except sh.ErrorReturnCode_1: + logger.debug('polkit auth agent not found, trying to launch it...') + run_polkit_auth_agent() -- cgit v1.2.3