From 12e238c81ed07879f1b55f327a67682233dc7ee3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 30 Jun 2014 14:36:52 -0300 Subject: Handle undefined danger flag. --- src/leap/bitmask/util/leap_argparse.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/leap') diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py index 0717aea5..b7428488 100644 --- a/src/leap/bitmask/util/leap_argparse.py +++ b/src/leap/bitmask/util/leap_argparse.py @@ -132,4 +132,9 @@ def get_options(): """ parser = build_parser() opts, unknown = parser.parse_known_args() + + # we add this option manually since it's not defined for 'release version' + if not IS_RELEASE_VERSION: + opts.danger = False + return opts -- cgit v1.2.3 From cae0889b4a8d915855c375f6d828659931e24df2 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 30 Jun 2014 14:51:53 -0300 Subject: Add the flag manually if it is release version. --- src/leap/bitmask/util/leap_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py index b7428488..c7fed0a3 100644 --- a/src/leap/bitmask/util/leap_argparse.py +++ b/src/leap/bitmask/util/leap_argparse.py @@ -134,7 +134,7 @@ def get_options(): opts, unknown = parser.parse_known_args() # we add this option manually since it's not defined for 'release version' - if not IS_RELEASE_VERSION: + if IS_RELEASE_VERSION: opts.danger = False return opts -- cgit v1.2.3 From f1b517e08bffbd3b625192e0c23d3bc0bf89d12b Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 2 Jul 2014 09:53:44 -0500 Subject: fix set syntax for 2.6 compat --- src/leap/bitmask/gui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 53a7d95a..8a5b8275 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1708,7 +1708,7 @@ class MainWindow(QtGui.QMainWindow): self._cancel_ongoing_defers() - self._services_being_stopped = {'imap', 'eip'} + self._services_being_stopped = set(('imap', 'eip')) imap_stopped = lambda: self._remove_service('imap') self._backend.signaler.imap_stopped.connect(imap_stopped) -- cgit v1.2.3 From 076cbbef6edf9d6dc8145f31d0803941d5ad6605 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 7 Jul 2014 18:13:22 -0300 Subject: Add support for fingerprint-gui's polkit agent. Closes #5880. --- src/leap/bitmask/services/eip/linuxvpnlauncher.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src/leap') diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py index 8ec0c050..1409d504 100644 --- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -74,6 +74,7 @@ def _is_auth_agent_running(): 'ps aux | grep "polkit-[m]ate-authentication-agent-1"', 'ps aux | grep "[l]xpolkit"', 'ps aux | grep "[g]nome-shell"', + 'ps aux | grep "[f]ingerprint-polkit-agent"', ] is_running = [commands.getoutput(cmd) for cmd in polkit_options] -- cgit v1.2.3 From 65a3e16ae1d240974535935e3cf898c45cc20870 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 8 Jul 2014 10:35:56 -0500 Subject: defer encryption --- src/leap/bitmask/services/mail/plumber.py | 3 ++- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py index c16a1fed..1ef0543e 100644 --- a/src/leap/bitmask/services/mail/plumber.py +++ b/src/leap/bitmask/services/mail/plumber.py @@ -83,7 +83,8 @@ def initialize_soledad(uuid, email, passwd, secrets, localdb, server_url, - cert_file) + cert_file, + defer_encryption=True) return soledad diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index db12fd80..aeced001 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -423,7 +423,8 @@ class SoledadBootstrapper(AbstractBootstrapper): local_db_path=local_db_path.encode(encoding), server_url=server_url, cert_file=cert_file.encode(encoding), - auth_token=auth_token) + auth_token=auth_token, + defer_encryption=True) # XXX All these errors should be handled by soledad itself, # and return a subclass of SoledadInitializationFailed @@ -448,7 +449,7 @@ class SoledadBootstrapper(AbstractBootstrapper): Raises SoledadSyncError if not successful. """ try: - self._soledad.sync() + self._soledad.sync(defer_decryption=True) except SSLError as exc: logger.error("%r" % (exc,)) raise SoledadSyncError("Failed to sync soledad") -- cgit v1.2.3 From 3fa1ec572a4c8ca752412e70af9ad0b9744933e0 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 17 Mar 2014 10:45:02 -0400 Subject: wait for decrypt during bootstrap --- .../services/soledad/soledadbootstrapper.py | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index aeced001..b9243add 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -21,6 +21,7 @@ import logging import os import socket import sys +import time from ssl import SSLError from sqlite3 import ProgrammingError as sqlite_ProgrammingError @@ -132,6 +133,9 @@ class SoledadBootstrapper(AbstractBootstrapper): MAX_INIT_RETRIES = 10 MAX_SYNC_RETRIES = 10 + WAIT_MAX_SECONDS = 600 + #WAIT_STEP_SECONDS = 1 + WAIT_STEP_SECONDS = 5 def __init__(self, signaler=None): AbstractBootstrapper.__init__(self, signaler) @@ -181,7 +185,6 @@ class SoledadBootstrapper(AbstractBootstrapper): :param uuid: the user uuid :type uuid: str or unicode """ - print "UUID ", uuid self._address = username self._password = password self._uuid = uuid @@ -356,12 +359,20 @@ class SoledadBootstrapper(AbstractBootstrapper): Do several retries to get an initial soledad sync. """ # and now, let's sync - sync_tries = 1 - while sync_tries <= self.MAX_SYNC_RETRIES: + sync_tries = self.MAX_SYNC_RETRIES + step = self.WAIT_STEP_SECONDS + max_wait = self.WAIT_MAX_SECONDS + while sync_tries > 0: + wait = 0 try: logger.debug("Trying to sync soledad....") self._try_soledad_sync() - logger.debug("Soledad has been synced.") + while self.soledad.syncing: + time.sleep(step) + wait += step + if wait >= max_wait: + raise SoledadSyncError("timeout!") + logger.debug("Soledad has been synced!") # so long, and thanks for all the fish return except SoledadSyncError: @@ -382,6 +393,7 @@ class SoledadBootstrapper(AbstractBootstrapper): self._signaler.SOLEDAD_INVALID_AUTH_TOKEN) raise except Exception as e: + # XXX release syncing lock logger.exception("Unhandled error while syncing " "soledad: %r" % (e,)) break @@ -449,6 +461,9 @@ class SoledadBootstrapper(AbstractBootstrapper): Raises SoledadSyncError if not successful. """ try: + logger.debug("BOOTSTRAPPER: trying to sync Soledad....") + # pass defer_decryption=False to get inline decryption + # for debugging. self._soledad.sync(defer_decryption=True) except SSLError as exc: logger.error("%r" % (exc,)) -- cgit v1.2.3 From 11c95ac4c8281b6f51aa0e61a4bf13159f664855 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 10 Jul 2014 11:10:08 -0300 Subject: Use preferred provider on first run. Closes #5813. --- src/leap/bitmask/gui/wizard.py | 48 +++++++++++++++++++++++++++++++------ src/leap/bitmask/provider/pinned.py | 10 ++++++-- 2 files changed, 49 insertions(+), 9 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index f66c553d..cb745c08 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -184,21 +184,55 @@ class Wizard(QtGui.QWizard): :param pinned: list of pinned providers :type pinned: list of str + + + How the combobox items are arranged: + ----------------------------------- + + First run: + + demo.bitmask.net + -- + pinned2.org + pinned1.org + pinned3.org + + After some usage: + + added-by-user.org + pinned-but-then-used.org + --- + demo.bitmask.net + pinned1.org + pinned3.org + pinned2.org + + In other words: + * There are two sections. + * Section one consists of all the providers that the user has used. + If this is empty, than use demo.bitmask.net for this section. + This list is sorted alphabetically. + * Section two consists of all the pinned or 'pre seeded' providers, + minus any providers that are now in section one. This last list + is in random order. """ ls = LeapSettings() - providers = ls.get_configured_providers() - if not providers and not pinned: + user_added = ls.get_configured_providers() + if not user_added and not pinned: self.ui.rbExistingProvider.setEnabled(False) self.ui.label_8.setEnabled(False) # 'https://' label self.ui.cbProviders.setEnabled(False) return - user_added = [] + user_added.sort() + + if not user_added: + user_added = [pinned.pop(0)] - # separate pinned providers from user added ones - for p in providers: - if p not in pinned: - user_added.append(p) + # separate unused pinned providers from user added ones + for p in user_added: + if p in pinned: + pinned.remove(p) if user_added: self.ui.cbProviders.addItems(user_added) diff --git a/src/leap/bitmask/provider/pinned.py b/src/leap/bitmask/provider/pinned.py index 38851621..6fd2fa70 100644 --- a/src/leap/bitmask/provider/pinned.py +++ b/src/leap/bitmask/provider/pinned.py @@ -32,6 +32,7 @@ class PinnedProviders(object): CONFIG_KEY = "config" CACERT_KEY = "cacert" + PREFERRED_PROVIDER = pinned_demobitmask.DOMAIN PROVIDERS = { pinned_demobitmask.DOMAIN: { @@ -50,11 +51,16 @@ class PinnedProviders(object): @classmethod def domains(self): """ - Return the domains that are pinned in here + Return the domains that are pinned in here. + The first domain in the list is the preferred one. :rtype: list of str """ - return self.PROVIDERS.keys() + domains = self.PROVIDERS.keys() + domains.remove(self.PREFERRED_PROVIDER) + domains.insert(0, self.PREFERRED_PROVIDER) + + return domains @classmethod def save_hardcoded(self, domain, provider_path, cacert_path): -- cgit v1.2.3 From 4da9d2fa3848fb2c6a6ea9982425c09b62fabb4b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 10 Jul 2014 11:13:50 -0300 Subject: Code style fixes. --- src/leap/bitmask/gui/wizard.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index cb745c08..4f67958f 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -83,7 +83,8 @@ class Wizard(QtGui.QWizard): self.ui.grpCheckProvider.setVisible(False) self._connect_and_track(self.ui.btnCheck.clicked, self._check_provider) - self._connect_and_track(self.ui.lnProvider.returnPressed, self._check_provider) + self._connect_and_track(self.ui.lnProvider.returnPressed, + self._check_provider) self._backend = backend self._backend_connect() @@ -98,22 +99,24 @@ class Wizard(QtGui.QWizard): self._provider_select_defer = None self._provider_setup_defer = None - self._connect_and_track(self.currentIdChanged, self._current_id_changed) + self._connect_and_track(self.currentIdChanged, + self._current_id_changed) - self._connect_and_track(self.ui.lnProvider.textChanged, self._enable_check) + self._connect_and_track(self.ui.lnProvider.textChanged, + self._enable_check) self._connect_and_track(self.ui.rbNewProvider.toggled, - lambda x: self._enable_check()) + lambda x: self._enable_check()) self._connect_and_track(self.ui.cbProviders.currentIndexChanged[int], - self._reset_provider_check) + self._reset_provider_check) self._connect_and_track(self.ui.lblUser.returnPressed, - self._focus_password) + self._focus_password) self._connect_and_track(self.ui.lblPassword.returnPressed, - self._focus_second_password) + self._focus_second_password) self._connect_and_track(self.ui.lblPassword2.returnPressed, - self._register) + self._register) self._connect_and_track(self.ui.btnRegister.clicked, - self._register) + self._register) self._connect_and_track(self.ui.rbExistingProvider.toggled, self._skip_provider_checks) -- cgit v1.2.3 From 37172578152f6f3d6ef169d79062c1d28ab0e98c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Tue, 8 Jul 2014 15:41:20 -0300 Subject: Add packaging for osx with py2app --- src/leap/bitmask/__init__.py | 6 ++++++ src/leap/bitmask/gui/__init__.py | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/__init__.py b/src/leap/bitmask/__init__.py index 0f733f26..03da1e2f 100644 --- a/src/leap/bitmask/__init__.py +++ b/src/leap/bitmask/__init__.py @@ -25,6 +25,12 @@ from pkg_resources import parse_version from leap.bitmask.util import first +# HACK: This is a hack so that py2app copies _scrypt.so to the right +# place, it can't be technically imported, but that doesn't matter +# because the import is never executed +if False: + import _scrypt + def _is_release_version(version): """ diff --git a/src/leap/bitmask/gui/__init__.py b/src/leap/bitmask/gui/__init__.py index 4b289442..94bf1fd5 100644 --- a/src/leap/bitmask/gui/__init__.py +++ b/src/leap/bitmask/gui/__init__.py @@ -17,5 +17,7 @@ """ init file for leap.gui """ -app = __import__("app", globals(), locals(), [], 2) -__all__ = [app] +# This was added for coverage and testing, but when doing the osx +# bundle with py2app it fails because of this, so commenting for now +# app = __import__("app", globals(), locals(), [], 2) +# __all__ = [app] -- cgit v1.2.3 From 1162895e124191996cc448816ad5b26bad266cfa Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 10 Jul 2014 11:59:42 -0700 Subject: bitmask-root: rip out all resolvconf code and simply rewrite all DNS packets to use the VPN nameserver. --- src/leap/bitmask/platform_init/initializers.py | 44 ++--------------------- src/leap/bitmask/services/eip/linuxvpnlauncher.py | 6 ---- 2 files changed, 2 insertions(+), 48 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index 384e1ec1..2d800703 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -373,30 +373,6 @@ def DarwinInitializer(): # Linux initializers # -def _get_missing_resolvconf_dialog(): - """ - Create a dialog for notifying about missing openresolv. - - :rtype: QtGui.QMessageBox instance - """ - msgstr = QtCore.QObject() - msgstr.NO_RESOLVCONF = msgstr.tr( - "Could not find resolvconf installed in your system.\n" - "Do you want to quit Bitmask now?") - - msgstr.EXPLAIN = msgstr.tr( - "Encrypted Internet needs resolvconf installed to work properly.\n" - "Please use your package manager to install it.\n") - - msg = QtGui.QMessageBox() - msg.setWindowTitle(msg.tr("Missing resolvconf framework")) - msg.setText(msgstr.NO_RESOLVCONF) - # but maybe the user really deserve to know more - msg.setInformativeText(msgstr.EXPLAIN) - msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - msg.setDefaultButton(QtGui.QMessageBox.Yes) - return msg - def _get_missing_complain_dialog(stuff): """ @@ -445,21 +421,6 @@ def _get_missing_complain_dialog(stuff): return msg -def _linux_check_resolvconf(): - """ - Raise a dialog warning about the lack of the resolvconf framework. - """ - RESOLVCONF_PATH = "/sbin/resolvconf" - missing = not os.path.isfile(RESOLVCONF_PATH) - - if missing: - msg = _get_missing_resolvconf_dialog() - ret = msg.exec_() - - if ret == QtGui.QMessageBox.Yes: - sys.exit() - - def _linux_install_missing_scripts(badexec, notfound): """ Try to install the missing helper files. @@ -509,9 +470,8 @@ def LinuxInitializer(): """ Raise a dialog if needed files are missing. - Missing files can be either system-wide resolvconf, bitmask-root, or - policykit file. The dialog will also be raised if some of those files are + Missing files can be either bitmask-root policykit file. + The dialog will also be raised if some of those files are found to have incorrect permissions. """ - _linux_check_resolvconf() check_missing() diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py index 1409d504..b6e47f25 100644 --- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -127,12 +127,6 @@ class LinuxVPNLauncher(VPNLauncher): # LinuxPolicyChecker will give us the right path if standalone. return LinuxPolicyChecker.get_polkit_path() - class RESOLVCONF_BIN_PATH(object): - def __call__(self): - return ("/usr/local/sbin/leap-resolvconf" if flags.STANDALONE else - "/sbin/resolvconf") - # this only will work with debian/ubuntu distros. - OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH) @classmethod -- cgit v1.2.3 From 2bf9a1c9768e13a148d4bc92687f8cae9fbc2198 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 11 Jul 2014 15:06:54 -0300 Subject: Use better message for the initial sync. Closes #5875. --- src/leap/bitmask/gui/mail_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index 5caef745..bb755b5c 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -304,7 +304,7 @@ class MailStatusWidget(QtGui.QWidget): ext_status = "" if req.event == proto.KEYMANAGER_LOOKING_FOR_KEY: - ext_status = self.tr("Looking for key for this user") + ext_status = self.tr("Initial sync in progress, please wait...") elif req.event == proto.KEYMANAGER_KEY_FOUND: ext_status = self.tr("Found key! Starting mail...") # elif req.event == proto.KEYMANAGER_KEY_NOT_FOUND: -- cgit v1.2.3 From 543296a62235d5303662720d3f341e1dc10d478e Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 9 Jul 2014 00:39:36 -0500 Subject: invoke mainwindow.quit only from parent pid because the fork happens after the registration of the signal handler, all children processes were inheriting the handler (and being passed a reference to the mainwindow object, ugh...) --- src/leap/bitmask/app.py | 67 +++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 6a7d6ff1..d0906b7c 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -49,7 +49,6 @@ from PySide import QtCore, QtGui from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags -from leap.bitmask.gui import locale_rc # noqa - silence pylint from leap.bitmask.gui.mainwindow import MainWindow from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only @@ -67,16 +66,39 @@ import codecs codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None) +import psutil + + +def kill_the_children(): + """ + Make sure no lingering subprocesses are left in case of a bad termination. + """ + me = os.getpid() + parent = psutil.Process(me) + print "Killing all the children processes..." + for child in parent.get_children(recursive=True): + try: + child.terminate() + except Exception as exc: + print exc + +# XXX This is currently broken, but we need to fix it to avoid +# orphaned processes in case of a crash. +#atexit.register(kill_the_children) + def sigint_handler(*args, **kwargs): """ Signal handler for SIGINT """ logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGINT catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() + parentpid = kwargs.get('parentpid', None) + pid = os.getpid() + if parentpid == pid: + if logger: + logger.debug("SIGINT catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() def sigterm_handler(*args, **kwargs): @@ -85,10 +107,13 @@ def sigterm_handler(*args, **kwargs): This handler is actually passed to twisted reactor """ logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGTERM catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() + parentpid = kwargs.get('parentpid', None) + pid = os.getpid() + if parentpid == pid: + if logger: + logger.debug("SIGTERM catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() def do_display_version(opts): @@ -203,32 +228,26 @@ def main(): app.setApplicationName("leap") app.setOrganizationDomain("leap.se") - # XXX --------------------------------------------------------- - # In quarantine, looks like we don't need it anymore. - # This dummy timer ensures that control is given to the outside - # loop, so we can hook our sigint handler. - #timer = QtCore.QTimer() - #timer.start(500) - #timer.timeout.connect(lambda: None) - # XXX --------------------------------------------------------- - window = MainWindow(bypass_checks=bypass_checks, start_hidden=start_hidden) - sigint_window = partial(sigint_handler, window, logger=logger) + mainpid = os.getpid() + sigint_window = partial(sigint_handler, window, + logger=logger, parentpid=mainpid) signal.signal(signal.SIGINT, sigint_window) # callable used in addSystemEventTrigger to handle SIGTERM - sigterm_window = partial(sigterm_handler, window, logger=logger) - - l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) - l.start(0.01) - + sigterm_window = partial(sigterm_handler, window, + logger=logger, parentpid=mainpid) # SIGTERM can't be handled the same way SIGINT is, since it's # caught by twisted. See _handleSignals method in # twisted/internet/base.py#L1150. So, addSystemEventTrigger # reactor's method is used. reactor.addSystemEventTrigger('before', 'shutdown', sigterm_window) + + l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) + l.start(0.01) + reactor.run() if __name__ == "__main__": -- cgit v1.2.3 From 5adf4d457ed964b7cc00def5d2be0dabd66fa04c Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 9 Jul 2014 00:40:14 -0500 Subject: call soledad close --- src/leap/bitmask/gui/mainwindow.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 8a5b8275..e53ab7f3 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1786,7 +1786,6 @@ class MainWindow(QtGui.QMainWindow): Final steps to quit the app, starting from here we don't care about running services or user interaction, just quitting. """ - logger.debug('Final quit...') # We can reach here because all the services are stopped or because a # timeout was triggered. Since we want to run this only once, we exit @@ -1796,6 +1795,10 @@ class MainWindow(QtGui.QMainWindow): self._finally_quitting = True + logger.debug('Closing soledad...') + self._backend.soledad_close() + logger.debug('Final quit...') + # Remove lockfiles on a clean shutdown. logger.debug('Cleaning pidfiles') if IS_WIN: -- cgit v1.2.3 From 3795dedd26fc239e143ca2a29b7e16d433f964ba Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 10 Jun 2014 17:05:06 -0300 Subject: Separate app.py and frontend_app.py logics. This prepares the scenario to run the frontend and the backend in different processes. --- src/leap/bitmask/app.py | 106 ++++++--------------------------------- src/leap/bitmask/frontend_app.py | 103 +++++++++++++++++++++++++++++++++++++ src/leap/bitmask/gui/__init__.py | 1 + 3 files changed, 119 insertions(+), 91 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index d0906b7c..f1d87d18 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -39,17 +39,13 @@ # M:::::::::::~NMMM7???7MMMM:::::::::::::::::::::::NMMMI??I7MMMM:::::::::::::M # M::::::::::::::7MMMMMMM+:::::::::::::::::::::::::::?MMMMMMMZ:::::::::::::::M # (thanks to: http://www.glassgiant.com/ascii/) -import signal -import sys +import multiprocessing import os - -from functools import partial - -from PySide import QtCore, QtGui +import sys from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags -from leap.bitmask.gui.mainwindow import MainWindow +from leap.bitmask.frontend_app import run_frontend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber @@ -59,9 +55,6 @@ from leap.bitmask.util.requirement_checker import check_requirements from leap.common.events import server as event_server from leap.mail import __version__ as MAIL_VERSION -from twisted.internet import reactor -from twisted.internet.task import LoopingCall - import codecs codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None) @@ -84,36 +77,7 @@ def kill_the_children(): # XXX This is currently broken, but we need to fix it to avoid # orphaned processes in case of a crash. -#atexit.register(kill_the_children) - - -def sigint_handler(*args, **kwargs): - """ - Signal handler for SIGINT - """ - logger = kwargs.get('logger', None) - parentpid = kwargs.get('parentpid', None) - pid = os.getpid() - if parentpid == pid: - if logger: - logger.debug("SIGINT catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() - - -def sigterm_handler(*args, **kwargs): - """ - Signal handler for SIGTERM. - This handler is actually passed to twisted reactor - """ - logger = kwargs.get('logger', None) - parentpid = kwargs.get('parentpid', None) - pid = os.getpid() - if parentpid == pid: - if logger: - logger.debug("SIGTERM catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() +# atexit.register(kill_the_children) def do_display_version(opts): @@ -141,7 +105,7 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct -def main(): +def start_app(): """ Starts the main event loop and launches the main window. """ @@ -149,8 +113,12 @@ def main(): opts = leap_argparse.get_options() do_display_version(opts) - bypass_checks = opts.danger - start_hidden = opts.start_hidden + options = { + 'bypass_checks': opts.danger, + 'start_hidden': opts.start_hidden, + 'debug': opts.debug, + 'log_file': opts.log_file, + } flags.STANDALONE = opts.standalone flags.OFFLINE = opts.offline @@ -202,53 +170,9 @@ def main(): logger.info('Starting app') - # We force the style if on KDE so that it doesn't load all the kde - # libs, which causes a compatibility issue in some systems. - # For more info, see issue #3194 - if flags.STANDALONE and os.environ.get("KDE_SESSION_UID") is not None: - sys.argv.append("-style") - sys.argv.append("Cleanlooks") - - app = QtGui.QApplication(sys.argv) - - # To test: - # $ LANG=es ./app.py - locale = QtCore.QLocale.system().name() - qtTranslator = QtCore.QTranslator() - if qtTranslator.load("qt_%s" % locale, ":/translations"): - app.installTranslator(qtTranslator) - appTranslator = QtCore.QTranslator() - if appTranslator.load("%s.qm" % locale[:2], ":/translations"): - app.installTranslator(appTranslator) - - # Needed for initializing qsettings it will write - # .config/leap/leap.conf top level app settings in a platform - # independent way - app.setOrganizationName("leap") - app.setApplicationName("leap") - app.setOrganizationDomain("leap.se") - - window = MainWindow(bypass_checks=bypass_checks, - start_hidden=start_hidden) - - mainpid = os.getpid() - sigint_window = partial(sigint_handler, window, - logger=logger, parentpid=mainpid) - signal.signal(signal.SIGINT, sigint_window) - - # callable used in addSystemEventTrigger to handle SIGTERM - sigterm_window = partial(sigterm_handler, window, - logger=logger, parentpid=mainpid) - # SIGTERM can't be handled the same way SIGINT is, since it's - # caught by twisted. See _handleSignals method in - # twisted/internet/base.py#L1150. So, addSystemEventTrigger - # reactor's method is used. - reactor.addSystemEventTrigger('before', 'shutdown', sigterm_window) - - l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) - l.start(0.01) - - reactor.run() + frontend = multiprocessing.Process(target=run_frontend, args=(options, )) + frontend.start() + if __name__ == "__main__": - main() + start_app() diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index e69de29b..ed67a77a 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# frontend_app.py +# Copyright (C) 2013, 2014 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 . +import signal +import sys +import os + +from functools import partial + +from PySide import QtCore, QtGui + +from leap.bitmask.config import flags +from leap.bitmask.gui import locale_rc # noqa - silence pylint +from leap.bitmask.gui.mainwindow import MainWindow +# from leap.bitmask.logs.utils import create_logger + +import logging +logger = logging.getLogger(__name__) + + +def sigint_handler(*args, **kwargs): + """ + Signal handler for SIGINT + """ + logger = kwargs.get('logger', None) + if logger: + logger.debug("SIGINT catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() + + +def sigterm_handler(*args, **kwargs): + """ + Signal handler for SIGTERM. + This handler is actually passed to twisted reactor + """ + logger = kwargs.get('logger', None) + if logger: + logger.debug("SIGTERM catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() + + +def run_frontend(options): + """ + Run the GUI for the application. + + :param options: a dict of options parsed from the command line. + :type options: dict + """ + bypass_checks = options["bypass_checks"] + start_hidden = options["start_hidden"] + + # We force the style if on KDE so that it doesn't load all the kde + # libs, which causes a compatibility issue in some systems. + # For more info, see issue #3194 + if flags.STANDALONE and os.environ.get("KDE_SESSION_UID") is not None: + sys.argv.append("-style") + sys.argv.append("Cleanlooks") + + qApp = QtGui.QApplication(sys.argv) + + # To test: + # $ LANG=es ./app.py + locale = QtCore.QLocale.system().name() + qtTranslator = QtCore.QTranslator() + if qtTranslator.load("qt_%s" % locale, ":/translations"): + qApp.installTranslator(qtTranslator) + appTranslator = QtCore.QTranslator() + if appTranslator.load("%s.qm" % locale[:2], ":/translations"): + qApp.installTranslator(appTranslator) + + # Needed for initializing qsettings it will write + # .config/leap/leap.conf top level app settings in a platform + # independent way + qApp.setOrganizationName("leap") + qApp.setApplicationName("leap") + qApp.setOrganizationDomain("leap.se") + + window = MainWindow(bypass_checks=bypass_checks, + start_hidden=start_hidden) + + sigint_window = partial(sigint_handler, window, logger=logger) + signal.signal(signal.SIGINT, sigint_window) + + sys.exit(qApp.exec_()) + + +if __name__ == '__main__': + run_frontend() diff --git a/src/leap/bitmask/gui/__init__.py b/src/leap/bitmask/gui/__init__.py index 94bf1fd5..bba02061 100644 --- a/src/leap/bitmask/gui/__init__.py +++ b/src/leap/bitmask/gui/__init__.py @@ -19,5 +19,6 @@ init file for leap.gui """ # This was added for coverage and testing, but when doing the osx # bundle with py2app it fails because of this, so commenting for now +# Also creates conflicts with the new frontend/backend separation. # app = __import__("app", globals(), locals(), [], 2) # __all__ = [app] -- cgit v1.2.3 From 1eae3af1906f95d9d2d76c205b61799d248f0e71 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 8 Jul 2014 16:45:43 -0300 Subject: Add base communication framework. --- src/leap/bitmask/backend/backend.py | 196 ++++++++++++++++++++++++++++++ src/leap/bitmask/backend/backend_proxy.py | 142 ++++++++++++++++++++++ src/leap/bitmask/backend/signaler.py | 140 +++++++++++++++++++++ src/leap/bitmask/backend/signaler_qt.py | 105 ++++++++++++++++ src/leap/bitmask/backend/utils.py | 43 +++++++ 5 files changed, 626 insertions(+) create mode 100644 src/leap/bitmask/backend/backend.py create mode 100644 src/leap/bitmask/backend/backend_proxy.py create mode 100644 src/leap/bitmask/backend/signaler.py create mode 100644 src/leap/bitmask/backend/signaler_qt.py create mode 100644 src/leap/bitmask/backend/utils.py (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py new file mode 100644 index 00000000..26c547b6 --- /dev/null +++ b/src/leap/bitmask/backend/backend.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +# encoding: utf-8 +import json +import threading +import time + +from twisted.internet import defer, reactor, threads + +import zmq +from zmq.auth.thread import ThreadAuthenticator + +from leap.bitmask.backend.api import API +from leap.bitmask.backend.utils import get_backend_certificates +from leap.bitmask.backend.signaler import Signaler + +import logging +logger = logging.getLogger(__name__) + + +class Backend(object): + """ + Backend server. + Receives signals from backend_proxy and emit signals if needed. + """ + PORT = '5556' + BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + + def __init__(self): + """ + Backend constructor, create needed instances. + """ + self._signaler = Signaler() + + self._do_work = threading.Event() # used to stop the worker thread. + self._zmq_socket = None + + self._ongoing_defers = [] + self._init_zmq() + + def _init_zmq(self): + """ + Configure the zmq components and connection. + """ + context = zmq.Context() + socket = context.socket(zmq.REP) + + # Start an authenticator for this context. + auth = ThreadAuthenticator(context) + auth.start() + auth.allow('127.0.0.1') + + # Tell authenticator to use the certificate in a directory + auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) + public, secret = get_backend_certificates() + socket.curve_publickey = public + socket.curve_secretkey = secret + socket.curve_server = True # must come before bind + + socket.bind(self.BIND_ADDR) + + self._zmq_socket = socket + + def _worker(self): + """ + Receive requests and send it to process. + + Note: we use a simple while since is less resource consuming than a + Twisted's LoopingCall. + """ + while self._do_work.is_set(): + # Wait for next request from client + try: + request = self._zmq_socket.recv(zmq.NOBLOCK) + self._zmq_socket.send("OK") + logger.debug("Received request: '{0}'".format(request)) + self._process_request(request) + except zmq.ZMQError as e: + if e.errno != zmq.EAGAIN: + raise + time.sleep(0.01) + + def _stop_reactor(self): + """ + Stop the Twisted reactor, but first wait a little for some threads to + complete their work. + + Note: this method needs to be run in a different thread so the + time.sleep() does not block and other threads can finish. + i.e.: + use threads.deferToThread(this_method) instead of this_method() + """ + wait_max = 5 # seconds + wait_step = 0.5 + wait = 0 + while self._ongoing_defers and wait < wait_max: + time.sleep(wait_step) + wait += wait_step + msg = "Waiting for running threads to finish... {0}/{1}" + msg = msg.format(wait, wait_max) + logger.debug(msg) + + # after a timeout we shut down the existing threads. + for d in self._ongoing_defers: + d.cancel() + + reactor.stop() + logger.debug("Twisted reactor stopped.") + + def run(self): + """ + Start the ZMQ server and run the loop to handle requests. + """ + self._signaler.start() + self._do_work.set() + threads.deferToThread(self._worker) + reactor.run() + + def stop(self): + """ + Stop the server and the zmq request parse loop. + """ + logger.debug("STOP received.") + self._signaler.stop() + self._do_work.clear() + threads.deferToThread(self._stop_reactor) + + def _process_request(self, request_json): + """ + Process a request and call the according method with the given + parameters. + + :param request_json: a json specification of a request. + :type request_json: str + """ + try: + # request = zmq.utils.jsonapi.loads(request_json) + # We use stdlib's json to ensure that we get unicode strings + request = json.loads(request_json) + api_method = request['api_method'] + kwargs = request['arguments'] or None + except Exception as e: + msg = "Malformed JSON data in Backend request '{0}'. Exc: {1!r}" + msg = msg.format(request_json, e) + msg = msg.format(request_json) + logger.critical(msg) + raise + + if api_method not in API: + logger.error("Invalid API call '{0}'".format(api_method)) + return + + self._run_in_thread(api_method, kwargs) + + def _run_in_thread(self, api_method, kwargs): + """ + Run the method name in a thread with the given arguments. + + :param api_method: the callable name to run in a thread. + :type api_method: str + :param kwargs: the arguments dict that will be sent to the callable. + :type kwargs: tuple + """ + func = getattr(self, api_method) + + method = func + if kwargs is not None: + method = lambda: func(**kwargs) + + logger.debug("Running method: '{0}' " + "with args: '{1}' in a thread".format(api_method, kwargs)) + + # run the action in a thread and keep track of it + d = threads.deferToThread(method) + d.addCallback(self._done_action, d) + d.addErrback(self._done_action, d) + self._ongoing_defers.append(d) + + def _done_action(self, failure, d): + """ + Remove the defer from the ongoing list. + + :param failure: the failure that triggered the errback. + None if no error. + :type failure: twisted.python.failure.Failure + :param d: defer to remove + :type d: twisted.internet.defer.Deferred + """ + if failure is not None: + if failure.check(defer.CancelledError): + logger.debug("A defer was cancelled.") + else: + logger.error("There was a failure - {0!r}".format(failure)) + logger.error(failure.getTraceback()) + + if d in self._ongoing_defers: + self._ongoing_defers.remove(d) diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py new file mode 100644 index 00000000..ae9cf5b1 --- /dev/null +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# encoding: utf-8 +import functools +import Queue +import threading +import time + +import zmq + +from leap.bitmask.backend.api import API, STOP_REQUEST +from leap.bitmask.backend.utils import get_backend_certificates + +import logging +logger = logging.getLogger(__name__) + + +class BackendProxy(object): + """ + The BackendProxy handles calls from the GUI and forwards (through ZMQ) + to the backend. + """ + PORT = '5556' + SERVER = "tcp://localhost:%s" % PORT + + def __init__(self): + self._socket = None + + # initialize ZMQ stuff: + context = zmq.Context() + logger.debug("Connecting to server...") + socket = context.socket(zmq.REQ) + + # public, secret = zmq.curve_keypair() + client_keys = zmq.curve_keypair() + socket.curve_publickey = client_keys[0] + socket.curve_secretkey = client_keys[1] + + # The client must know the server's public key to make a CURVE + # connection. + public, _ = get_backend_certificates() + socket.curve_serverkey = public + + socket.setsockopt(zmq.RCVTIMEO, 1000) + socket.connect(self.SERVER) + self._socket = socket + + self._call_queue = Queue.Queue() + self._worker_caller = threading.Thread(target=self._worker) + self._worker_caller.start() + + def _worker(self): + """ + Worker loop that processes the Queue of pending requests to do. + """ + while True: + try: + request = self._call_queue.get(block=False) + # break the loop after sending the 'stop' action to the + # backend. + if request == STOP_REQUEST: + break + + self._send_request(request) + except Queue.Empty: + pass + time.sleep(0.01) + + logger.debug("BackendProxy worker stopped.") + + def _api_call(self, *args, **kwargs): + """ + Call the `api_method` method in backend (through zmq). + + :param kwargs: named arguments to forward to the backend api method. + :type kwargs: dict + + Note: is mandatory to have the kwarg 'api_method' defined. + """ + if args: + # Use a custom message to be more clear about using kwargs *only* + raise Exception("All arguments need to be kwargs!") + + api_method = kwargs.pop('api_method', None) + if api_method is None: + raise Exception("Missing argument, no method name specified.") + + request = { + 'api_method': api_method, + 'arguments': kwargs, + } + + try: + request_json = zmq.utils.jsonapi.dumps(request) + except Exception as e: + msg = ("Error serializing request into JSON.\n" + "Exception: {0} Data: {1}") + msg = msg.format(e, request) + logger.critical(msg) + raise + + # queue the call in order to handle the request in a thread safe way. + self._call_queue.put(request_json) + + if api_method == STOP_REQUEST: + self._call_queue.put(STOP_REQUEST) + + def _send_request(self, request): + """ + Send the given request to the server. + This is used from a thread safe loop in order to avoid sending a + request without receiving a response from a previous one. + + :param request: the request to send. + :type request: str + """ + logger.debug("Sending request to backend: {0}".format(request)) + self._socket.send(request) + + try: + # Get the reply. + response = self._socket.recv() + msg = "Received reply for '{0}' -> '{1}'".format(request, response) + logger.debug(msg) + except zmq.error.Again as e: + msg = "Timeout error contacting backend. {0!r}".format(e) + logger.critical(msg) + + def __getattribute__(self, name): + """ + This allows the user to do: + bp = BackendProxy() + bp.some_method() + + Just by having defined 'some_method' in the API + + :param name: the attribute name that is requested. + :type name: str + """ + if name in API: + return functools.partial(self._api_call, api_method=name) + else: + return object.__getattribute__(self, name) diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py new file mode 100644 index 00000000..d96015f4 --- /dev/null +++ b/src/leap/bitmask/backend/signaler.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# encoding: utf-8 +import Queue +import threading +import time + +import zmq + +from leap.bitmask.backend.api import SIGNALS +from leap.bitmask.backend.utils import get_frontend_certificates + +import logging +logger = logging.getLogger(__name__) + + +class Signaler(object): + """ + Signaler client. + Receives signals from the backend and sends to the signaling server. + """ + PORT = "5667" + SERVER = "tcp://localhost:%s" % PORT + + def __init__(self): + """ + Initialize the ZMQ socket to talk to the signaling server. + """ + context = zmq.Context() + logger.debug("Connecting to signaling server...") + socket = context.socket(zmq.REQ) + + # public, secret = zmq.curve_keypair() + client_keys = zmq.curve_keypair() + socket.curve_publickey = client_keys[0] + socket.curve_secretkey = client_keys[1] + + # The client must know the server's public key to make a CURVE + # connection. + public, _ = get_frontend_certificates() + socket.curve_serverkey = public + + socket.setsockopt(zmq.RCVTIMEO, 1000) + socket.connect(self.SERVER) + self._socket = socket + + self._signal_queue = Queue.Queue() + + self._do_work = threading.Event() # used to stop the worker thread. + self._worker_signaler = threading.Thread(target=self._worker) + + def __getattribute__(self, name): + """ + This allows the user to do: + S = Signaler() + S.SOME_SIGNAL + + Just by having defined 'some_signal' in _SIGNALS + + :param name: the attribute name that is requested. + :type name: str + """ + if name in SIGNALS: + return name + else: + return object.__getattribute__(self, name) + + def signal(self, signal, data=None): + """ + Sends a signal to the signaling server. + + :param signal: the signal to send. + :type signal: str + """ + if signal not in SIGNALS: + raise Exception("Unknown signal: '{0}'".format(signal)) + + request = { + 'signal': signal, + 'data': data, + } + + try: + request_json = zmq.utils.jsonapi.dumps(request) + except Exception as e: + msg = ("Error serializing request into JSON.\n" + "Exception: {0} Data: {1}") + msg = msg.format(e, request) + logger.critical(msg) + raise + + # queue the call in order to handle the request in a thread safe way. + self._signal_queue.put(request_json) + + def _worker(self): + """ + Worker loop that processes the Queue of pending requests to do. + """ + while self._do_work.is_set(): + try: + request = self._signal_queue.get(block=False) + self._send_request(request) + except Queue.Empty: + pass + time.sleep(0.01) + + logger.debug("Signaler thread stopped.") + + def start(self): + """ + Start the Signaler worker. + """ + self._do_work.set() + self._worker_signaler.start() + + def stop(self): + """ + Stop the Signaler worker. + """ + self._do_work.clear() + + def _send_request(self, request): + """ + Send the given request to the server. + This is used from a thread safe loop in order to avoid sending a + request without receiving a response from a previous one. + + :param request: the request to send. + :type request: str + """ + logger.debug("Signaling '{0}'".format(request)) + self._socket.send(request) + + # Get the reply. + try: + response = self._socket.recv() + msg = "Received reply for '{0}' -> '{1}'".format(request, response) + logger.debug(msg) + except zmq.error.Again as e: + msg = "Timeout error contacting signaler. {0!r}".format(e) + logger.critical(msg) diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py new file mode 100644 index 00000000..cf49df91 --- /dev/null +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# encoding: utf-8 +import threading +import time + +from PySide import QtCore + +import zmq +from zmq.auth.thread import ThreadAuthenticator + +from leap.bitmask.backend.api import SIGNALS +from leap.bitmask.backend.utils import get_frontend_certificates + +import logging +logger = logging.getLogger(__name__) + + +class SignalerQt(QtCore.QThread): + """ + Signaling server. + Receives signals from the signaling client and emit Qt signals for the GUI. + """ + PORT = "5667" + BIND_ADDR = "tcp://127.0.0.1:%s" % PORT + + def __init__(self): + QtCore.QThread.__init__(self) + self._do_work = threading.Event() + self._do_work.set() + + def run(self): + """ + Start a loop to process the ZMQ requests from the signaler client. + """ + logger.debug("Running SignalerQt loop") + context = zmq.Context() + socket = context.socket(zmq.REP) + + # Start an authenticator for this context. + auth = ThreadAuthenticator(context) + auth.start() + auth.allow('127.0.0.1') + + # Tell authenticator to use the certificate in a directory + auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY) + public, secret = get_frontend_certificates() + socket.curve_publickey = public + socket.curve_secretkey = secret + socket.curve_server = True # must come before bind + + socket.bind(self.BIND_ADDR) + + while self._do_work.is_set(): + # Wait for next request from client + try: + request = socket.recv(zmq.NOBLOCK) + logger.debug("Received request: '{0}'".format(request)) + socket.send("OK") + self._process_request(request) + except zmq.ZMQError as e: + if e.errno != zmq.EAGAIN: + raise + time.sleep(0.01) + + logger.debug("SignalerQt thread stopped.") + + def stop(self): + """ + Stop the SignalerQt blocking loop. + """ + self._do_work.clear() + + def _process_request(self, request_json): + """ + Process a request and call the according method with the given + parameters. + + :param request_json: a json specification of a request. + :type request_json: str + """ + try: + request = zmq.utils.jsonapi.loads(request_json) + signal = request['signal'] + data = request['data'] + except Exception as e: + msg = "Malformed JSON data in Signaler request '{0}'. Exc: {1!r}" + msg = msg.format(request_json, e) + logger.critical(msg) + raise + + if signal not in SIGNALS: + logger.error("Unknown signal received, '{0}'".format(signal)) + return + + try: + qt_signal = getattr(self, signal) + except Exception: + logger.warning("Signal not implemented, '{0}'".format(signal)) + return + + logger.debug("Emitting '{0}'".format(signal)) + if data is None: + qt_signal.emit() + else: + qt_signal.emit(data) diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py new file mode 100644 index 00000000..5fe59a62 --- /dev/null +++ b/src/leap/bitmask/backend/utils.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# encoding: utf-8 +import os +import shutil + +import zmq.auth + +from leap.bitmask.util import get_path_prefix + +KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates') + + +def generate_certificates(): + """ + Generate client and server CURVE certificate files. + """ + # Create directory for certificates, remove old content if necessary + if os.path.exists(KEYS_DIR): + shutil.rmtree(KEYS_DIR) + os.mkdir(KEYS_DIR) + + # create new keys in certificates dir + # public_file, secret_file = create_certificates(...) + zmq.auth.create_certificates(KEYS_DIR, "frontend") + zmq.auth.create_certificates(KEYS_DIR, "backend") + + +def get_frontend_certificates(): + """ + Return the frontend's public and secret certificates. + """ + frontend_secret_file = os.path.join(KEYS_DIR, "frontend.key_secret") + public, secret = zmq.auth.load_certificate(frontend_secret_file) + return public, secret + + +def get_backend_certificates(base_dir='.'): + """ + Return the backend's public and secret certificates. + """ + backend_secret_file = os.path.join(KEYS_DIR, "backend.key_secret") + public, secret = zmq.auth.load_certificate(backend_secret_file) + return public, secret -- cgit v1.2.3 From 787c799077cd19f5f87b3c2f26c66df7e8b48023 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 25 Jun 2014 12:19:00 -0300 Subject: Add API/SIGNALs definition. --- src/leap/bitmask/backend/api.py | 130 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/leap/bitmask/backend/api.py (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py new file mode 100644 index 00000000..9e0f9ab8 --- /dev/null +++ b/src/leap/bitmask/backend/api.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Backend available API and SIGNALS definition. +""" +STOP_REQUEST = "stop" + +API = ( + STOP_REQUEST, # this method needs to be defined in order to support the + # backend stop action + + "eip_can_start", + "eip_cancel_setup", + "eip_check_dns", + "eip_get_gateways_list", + "eip_get_initialized_providers", + "eip_setup", + "eip_start", + "eip_stop", + "eip_terminate", + "imap_start_service", + "imap_stop_service", + "keymanager_export_keys", + "keymanager_get_key_details", + "keymanager_list_keys", + "provider_bootstrap", + "provider_cancel_setup", + "provider_get_all_services", + "provider_get_details", + "provider_get_pinned_providers", + "provider_get_supported_services", + "provider_setup", + "smtp_start_service", + "smtp_stop_service", + "soledad_bootstrap", + "soledad_cancel_bootstrap", + "soledad_change_password", + "soledad_close", + "soledad_load_offline", + "tear_fw_down", + "user_cancel_login", + "user_change_password", + "user_get_logged_in_status", + "user_login", + "user_logout", + "user_register", +) + + +SIGNALS = ( + "backend_bad_call", + "eip_alien_openvpn_already_running", + "eip_can_start", + "eip_cancelled_setup", + "eip_cannot_start", + "eip_client_certificate_ready", + "eip_config_ready", + "eip_connected", + "eip_connection_aborted", + "eip_connection_died", + "eip_disconnected", + "eip_dns_error", + "eip_dns_ok", + "eip_get_gateways_list", + "eip_get_gateways_list_error", + "eip_get_initialized_providers", + "eip_network_unreachable", + "eip_no_pkexec_error", + "eip_no_polkit_agent_error", + "eip_no_tun_kext_error", + "eip_openvpn_already_running", + "eip_openvpn_not_found_error", + "eip_process_finished", + "eip_process_restart_ping", + "eip_process_restart_tls", + "eip_state_changed", + "eip_status_changed", + "eip_stopped", + "eip_tear_fw_down", + "eip_uninitialized_provider", + "eip_vpn_launcher_exception", + "imap_stopped", + "keymanager_export_error", + "keymanager_export_ok", + "keymanager_import_addressmismatch", + "keymanager_import_datamismatch", + "keymanager_import_ioerror", + "keymanager_import_missingkey", + "keymanager_import_ok", + "keymanager_key_details", + "keymanager_keys_list", + "prov_cancelled_setup", + "prov_check_api_certificate", + "prov_check_ca_fingerprint", + "prov_download_ca_cert", + "prov_download_provider_info", + "prov_get_all_services", + "prov_get_details", + "prov_get_pinned_providers", + "prov_get_supported_services", + "prov_https_connection", + "prov_name_resolution", + "prov_problem_with_provider", + "prov_unsupported_api", + "prov_unsupported_client", + "soledad_bootstrap_failed", + "soledad_bootstrap_finished", + "soledad_cancelled_bootstrap", + "soledad_invalid_auth_token", + "soledad_offline_failed", + "soledad_offline_finished", + "soledad_password_change_error", + "soledad_password_change_ok", + "srp_auth_bad_user_or_password", + "srp_auth_connection_error", + "srp_auth_error", + "srp_auth_ok", + "srp_auth_server_error", + "srp_logout_error", + "srp_logout_ok", + "srp_not_logged_in_error", + "srp_password_change_badpw", + "srp_password_change_error", + "srp_password_change_ok", + "srp_registration_failed", + "srp_registration_finished", + "srp_registration_taken", + "srp_status_logged_in", + "srp_status_not_logged_in", +) -- cgit v1.2.3 From 4d5e56dacf33465df5d195ada2855c86ee23a21f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 19 Jun 2014 16:54:34 -0300 Subject: Add license headers. --- src/leap/bitmask/backend/api.py | 18 ++++++++++++++++-- src/leap/bitmask/backend/backend.py | 18 ++++++++++++++++-- src/leap/bitmask/backend/backend_proxy.py | 18 ++++++++++++++++-- src/leap/bitmask/backend/signaler.py | 18 ++++++++++++++++-- src/leap/bitmask/backend/signaler_qt.py | 18 ++++++++++++++++-- src/leap/bitmask/backend/utils.py | 18 ++++++++++++++++-- 6 files changed, 96 insertions(+), 12 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index 9e0f9ab8..012b3cbc 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# api.py +# Copyright (C) 2013, 2014 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 . """ Backend available API and SIGNALS definition. """ diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 26c547b6..5f696f75 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# backend.py +# Copyright (C) 2013, 2014 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 . import json import threading import time diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index ae9cf5b1..3c8e5d0f 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# backend_proxy.py +# Copyright (C) 2013, 2014 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 . import functools import Queue import threading diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index d96015f4..f8753771 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# signaler.py +# Copyright (C) 2013, 2014 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 . import Queue import threading import time diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py index cf49df91..dabd6662 100644 --- a/src/leap/bitmask/backend/signaler_qt.py +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# signaler_qt.py +# Copyright (C) 2013, 2014 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 . import threading import time diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py index 5fe59a62..5d600689 100644 --- a/src/leap/bitmask/backend/utils.py +++ b/src/leap/bitmask/backend/utils.py @@ -1,5 +1,19 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- +# utils.py +# Copyright (C) 2013, 2014 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 . import os import shutil -- cgit v1.2.3 From 8d5ca2dda0f014cc036768a5eef343e568bb292d Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 19 Jun 2014 14:58:43 -0300 Subject: Use new frontend/backend structure in LEAP implementation. --- src/leap/bitmask/backend/leapbackend.py | 278 ++++++-------------- src/leap/bitmask/backend/leapsignaler.py | 433 ++++++------------------------- 2 files changed, 155 insertions(+), 556 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index 3c5222f4..cc7227ad 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # leapbackend.py -# Copyright (C) 2013 LEAP +# Copyright (C) 2013, 2014 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 @@ -15,178 +15,60 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ -Backend for GUI/Logic communication. +Backend for everything """ import logging - -from Queue import Queue, Empty - -from twisted.internet import reactor -from twisted.internet import threads, defer -from twisted.internet.task import LoopingCall +import signal import zope.interface import zope.proxy -from leap.bitmask.backend.leapsignaler import Signaler from leap.bitmask.backend import components +from leap.bitmask.backend.backend import Backend logger = logging.getLogger(__name__) -class Backend(object): +class LeapBackend(Backend): """ - Backend for everything, the UI should only use this class. + Backend server subclass, used to implement the API methods. """ - - PASSED_KEY = "passed" - ERROR_KEY = "error" - def __init__(self, bypass_checks=False): """ Constructor for the backend. """ - # Components map for the commands received - self._components = {} - - # Ongoing defers that will be cancelled at stop time - self._ongoing_defers = [] - - # Signaler object to translate commands into Qt signals - self._signaler = Signaler() + Backend.__init__(self) # Objects needed by several components, so we make a proxy and pass # them around self._soledad_proxy = zope.proxy.ProxyBase(None) self._keymanager_proxy = zope.proxy.ProxyBase(None) - # Component registration - self._register(components.Provider(self._signaler, bypass_checks)) - self._register(components.Register(self._signaler)) - self._register(components.Authenticate(self._signaler)) - self._register(components.EIP(self._signaler)) - self._register(components.Soledad(self._soledad_proxy, - self._keymanager_proxy, - self._signaler)) - self._register(components.Keymanager(self._keymanager_proxy, - self._signaler)) - self._register(components.Mail(self._soledad_proxy, - self._keymanager_proxy, - self._signaler)) - - # We have a looping call on a thread executing all the - # commands in queue. Right now this queue is an actual Queue - # object, but it'll become the zmq recv_multipart queue - self._lc = LoopingCall(threads.deferToThread, self._worker) - - # Temporal call_queue for worker, will be replaced with - # recv_multipart os something equivalent in the loopingcall - self._call_queue = Queue() - - @property - def signaler(self): - """ - Public signaler access to let the UI connect to its signals. - """ - return self._signaler - - def start(self): - """ - Starts the looping call - """ - logger.debug("Starting worker...") - self._lc.start(0.01) - - def stop(self): - """ - Stops the looping call and tries to cancel all the defers. - """ - reactor.callLater(2, self._stop) - - def _stop(self): - """ - Delayed stopping of worker. Called from `stop`. - """ - logger.debug("Stopping worker...") - if self._lc.running: - self._lc.stop() - else: - logger.warning("Looping call is not running, cannot stop") - - logger.debug("Cancelling ongoing defers...") - while len(self._ongoing_defers) > 0: - d = self._ongoing_defers.pop() - d.cancel() - logger.debug("Defers cancelled.") - - def _register(self, component): - """ - Registers a component in this backend - - :param component: Component to register - :type component: any object that implements ILEAPComponent - """ - # TODO: assert that the component implements the interfaces - # expected - try: - self._components[component.key] = component - except Exception: - logger.error("There was a problem registering %s" % (component,)) - - def _signal_back(self, _, signal): - """ - Helper method to signal back (callback like behavior) to the - UI that an operation finished. + # Component instances creation + self._provider = components.Provider(self._signaler, bypass_checks) + self._register = components.Register(self._signaler) + self._authenticate = components.Authenticate(self._signaler) + self._eip = components.EIP(self._signaler) + self._soledad = components.Soledad(self._soledad_proxy, + self._keymanager_proxy, + self._signaler) + self._keymanager = components.Keymanager(self._keymanager_proxy, + self._signaler) + self._mail = components.Mail(self._soledad_proxy, + self._keymanager_proxy, + self._signaler) - :param signal: signal name - :type signal: str + def _check_type(self, obj, expected_type): """ - self._signaler.signal(signal) + Check the type of a parameter. - def _worker(self): + :param obj: object to check its type. + :type obj: any type + :param expected_type: the expected type of the object. + :type expected_type: type """ - Worker method, called from a different thread and as a part of - a looping call - """ - try: - # this'll become recv_multipart - cmd = self._call_queue.get(block=False) - - # cmd is: component, method, signalback, *args - func = getattr(self._components[cmd[0]], cmd[1]) - d = func(*cmd[3:]) - if d is not None: # d may be None if a defer chain is cancelled. - # A call might not have a callback signal, but if it does, - # we add it to the chain - if cmd[2] is not None: - d.addCallbacks(self._signal_back, logger.error, cmd[2]) - d.addCallbacks(self._done_action, logger.error, - callbackKeywords={"d": d}) - d.addErrback(logger.error) - self._ongoing_defers.append(d) - except Empty: - # If it's just empty we don't have anything to do. - pass - except defer.CancelledError: - logger.debug("defer cancelled somewhere (CancelledError).") - except Exception as e: - # But we log the rest - logger.exception("Unexpected exception: {0!r}".format(e)) - - def _done_action(self, _, d): - """ - Remover of the defer once it's done - - :param d: defer to remove - :type d: twisted.internet.defer.Deferred - """ - if d in self._ongoing_defers: - self._ongoing_defers.remove(d) - - # XXX: Temporal interface until we migrate to zmq - # We simulate the calls to zmq.send_multipart. Once we separate - # this in two processes, the methods bellow can be changed to - # send_multipart and this backend class will be really simple. + if not isinstance(obj, expected_type): + raise TypeError("The parameter type is incorrect.") def provider_setup(self, provider): """ @@ -202,13 +84,13 @@ class Backend(object): prov_https_connection -> { PASSED_KEY: bool, ERROR_KEY: str } prov_download_provider_info -> { PASSED_KEY: bool, ERROR_KEY: str } """ - self._call_queue.put(("provider", "setup_provider", None, provider)) + self._provider.setup_provider(provider) def provider_cancel_setup(self): """ Cancel the ongoing setup provider (if any). """ - self._call_queue.put(("provider", "cancel_setup_provider", None)) + self._provider.cancel_setup_provider() def provider_bootstrap(self, provider): """ @@ -223,7 +105,7 @@ class Backend(object): prov_check_ca_fingerprint -> {PASSED_KEY: bool, ERROR_KEY: str} prov_check_api_certificate -> {PASSED_KEY: bool, ERROR_KEY: str} """ - self._call_queue.put(("provider", "bootstrap", None, provider)) + self._provider.bootstrap(provider) def provider_get_supported_services(self, domain): """ @@ -235,8 +117,7 @@ class Backend(object): Signals: prov_get_supported_services -> list of unicode """ - self._call_queue.put(("provider", "get_supported_services", None, - domain)) + self._provider.get_supported_services(domain) def provider_get_all_services(self, providers): """ @@ -248,13 +129,11 @@ class Backend(object): Signals: prov_get_all_services -> list of unicode """ - self._call_queue.put(("provider", "get_all_services", None, - providers)) + self._provider.get_all_services(providers) def provider_get_details(self, domain, lang): """ - Signal a ProviderConfigLight object with the current ProviderConfig - settings. + Signal a dict with the current ProviderConfig settings. :param domain: the domain name of the provider. :type domain: str @@ -262,9 +141,9 @@ class Backend(object): :type lang: str Signals: - prov_get_details -> ProviderConfigLight + prov_get_details -> dict """ - self._call_queue.put(("provider", "get_details", None, domain, lang)) + self._provider.get_details(domain, lang) def provider_get_pinned_providers(self): """ @@ -273,7 +152,7 @@ class Backend(object): Signals: prov_get_pinned_providers -> list of provider domains """ - self._call_queue.put(("provider", "get_pinned_providers", None)) + self._provider.get_pinned_providers() def user_register(self, provider, username, password): """ @@ -291,8 +170,7 @@ class Backend(object): srp_registration_taken srp_registration_failed """ - self._call_queue.put(("register", "register_user", None, provider, - username, password)) + self._register.register_user(provider, username, password) def eip_setup(self, provider, skip_network=False): """ @@ -309,14 +187,13 @@ class Backend(object): eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str} eip_cancelled_setup """ - self._call_queue.put(("eip", "setup_eip", None, provider, - skip_network)) + self._eip.setup_eip(provider, skip_network) def eip_cancel_setup(self): """ Cancel the ongoing setup EIP (if any). """ - self._call_queue.put(("eip", "cancel_setup_eip", None)) + self._eip.cancel_setup_eip() def eip_start(self, restart=False): """ @@ -343,7 +220,7 @@ class Backend(object): :param restart: whether is is a restart. :type restart: bool """ - self._call_queue.put(("eip", "start", None, restart)) + self._eip.start(restart) def eip_stop(self, shutdown=False, restart=False, failed=False): """ @@ -355,13 +232,13 @@ class Backend(object): :param restart: whether this is part of a restart. :type restart: bool """ - self._call_queue.put(("eip", "stop", None, shutdown, restart)) + self._eip.stop(shutdown, restart) def eip_terminate(self): """ Terminate the EIP service, not necessarily in a nice way. """ - self._call_queue.put(("eip", "terminate", None)) + self._eip.terminate() def eip_get_gateways_list(self, domain): """ @@ -370,16 +247,12 @@ class Backend(object): :param domain: the domain to get the gateways. :type domain: str - # TODO discuss how to document the expected result object received of - # the signal - :signal type: list of str - Signals: eip_get_gateways_list -> list of unicode eip_get_gateways_list_error eip_uninitialized_provider """ - self._call_queue.put(("eip", "get_gateways_list", None, domain)) + self._eip.get_gateways_list(domain) def eip_get_initialized_providers(self, domains): """ @@ -392,8 +265,7 @@ class Backend(object): eip_get_initialized_providers -> list of tuple(unicode, bool) """ - self._call_queue.put(("eip", "get_initialized_providers", - None, domains)) + self._eip.get_initialized_providers(domains) def eip_can_start(self, domain): """ @@ -406,8 +278,7 @@ class Backend(object): eip_can_start eip_cannot_start """ - self._call_queue.put(("eip", "can_start", - None, domain)) + self._eip.can_start(domain) def eip_check_dns(self, domain): """ @@ -420,13 +291,13 @@ class Backend(object): eip_dns_ok eip_dns_error """ - self._call_queue.put(("eip", "check_dns", None, domain)) + self._eip.check_dns(domain) def tear_fw_down(self): """ Signal the need to tear the fw down. """ - self._call_queue.put(("eip", "tear_fw_down", None)) + self._eip.tear_fw_down() def user_login(self, provider, username, password): """ @@ -447,8 +318,7 @@ class Backend(object): srp_auth_connection_error srp_auth_error """ - self._call_queue.put(("authenticate", "login", None, provider, - username, password)) + self._authenticate.login(provider, username, password) def user_logout(self): """ @@ -459,13 +329,13 @@ class Backend(object): srp_logout_error srp_not_logged_in_error """ - self._call_queue.put(("authenticate", "logout", None)) + self._authenticate.logout() def user_cancel_login(self): """ Cancel the ongoing login (if any). """ - self._call_queue.put(("authenticate", "cancel_login", None)) + self._authenticate.cancel_login() def user_change_password(self, current_password, new_password): """ @@ -482,8 +352,7 @@ class Backend(object): srp_password_change_badpw srp_password_change_error """ - self._call_queue.put(("authenticate", "change_password", None, - current_password, new_password)) + self._authenticate.change_password(current_password, new_password) def soledad_change_password(self, new_password): """ @@ -498,8 +367,7 @@ class Backend(object): srp_password_change_badpw srp_password_change_error """ - self._call_queue.put(("soledad", "change_password", None, - new_password)) + self._soledad.change_password(new_password) def user_get_logged_in_status(self): """ @@ -509,7 +377,7 @@ class Backend(object): srp_status_logged_in srp_status_not_logged_in """ - self._call_queue.put(("authenticate", "get_logged_in_status", None)) + self._authenticate.get_logged_in_status() def soledad_bootstrap(self, username, domain, password): """ @@ -527,8 +395,10 @@ class Backend(object): soledad_bootstrap_failed soledad_invalid_auth_token """ - self._call_queue.put(("soledad", "bootstrap", None, - username, domain, password)) + self._check_type(username, unicode) + self._check_type(domain, unicode) + self._check_type(password, unicode) + self._soledad.bootstrap(username, domain, password) def soledad_load_offline(self, username, password, uuid): """ @@ -543,20 +413,19 @@ class Backend(object): Signals: """ - self._call_queue.put(("soledad", "load_offline", None, - username, password, uuid)) + self._soledad.load_offline(username, password, uuid) def soledad_cancel_bootstrap(self): """ Cancel the ongoing soledad bootstrapping process (if any). """ - self._call_queue.put(("soledad", "cancel_bootstrap", None)) + self._soledad.cancel_bootstrap() def soledad_close(self): """ Close soledad database. """ - self._call_queue.put(("soledad", "close", None)) + self._soledad.close() def keymanager_list_keys(self): """ @@ -565,7 +434,7 @@ class Backend(object): Signals: keymanager_keys_list -> list """ - self._call_queue.put(("keymanager", "list_keys", None)) + self._keymanager.list_keys() def keymanager_export_keys(self, username, filename): """ @@ -580,8 +449,7 @@ class Backend(object): keymanager_export_ok keymanager_export_error """ - self._call_queue.put(("keymanager", "export_keys", None, - username, filename)) + self._keymanager.export_keys(username, filename) def keymanager_get_key_details(self, username): """ @@ -593,7 +461,7 @@ class Backend(object): Signals: keymanager_key_details """ - self._call_queue.put(("keymanager", "get_key_details", None, username)) + self._keymanager.get_key_details(username) def smtp_start_service(self, full_user_id, download_if_needed=False): """ @@ -605,8 +473,7 @@ class Backend(object): for the file :type download_if_needed: bool """ - self._call_queue.put(("mail", "start_smtp_service", None, - full_user_id, download_if_needed)) + self._mail.start_smtp_service(full_user_id, download_if_needed) def imap_start_service(self, full_user_id, offline=False): """ @@ -617,14 +484,13 @@ class Backend(object): :param offline: whether imap should start in offline mode or not. :type offline: bool """ - self._call_queue.put(("mail", "start_imap_service", None, - full_user_id, offline)) + self._mail.start_imap_service(full_user_id, offline) def smtp_stop_service(self): """ Stop the SMTP service. """ - self._call_queue.put(("mail", "stop_smtp_service", None)) + self._mail.stop_smtp_service() def imap_stop_service(self): """ @@ -633,4 +499,12 @@ class Backend(object): Signals: imap_stopped """ - self._call_queue.put(("mail", "stop_imap_service", None)) + self._mail.stop_imap_service() + + +def run_backend(bypass_checks=False): + # Ensure that the application quits using CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + + backend = LeapBackend(bypass_checks=bypass_checks) + backend.run() diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py index da8908fd..47df0911 100644 --- a/src/leap/bitmask/backend/leapsignaler.py +++ b/src/leap/bitmask/backend/leapsignaler.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# components.py +# leapsignaler.py # Copyright (C) 2013 LEAP # # This program is free software: you can redistribute it and/or modify @@ -14,372 +14,97 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -""" -Signaler for Backend/Frontend communication. -""" -import logging - from PySide import QtCore -logger = logging.getLogger(__name__) +from leap.bitmask.backend.signaler_qt import SignalerQt -class Signaler(QtCore.QObject): +class LeapSignaler(SignalerQt): """ - Signaler object, handles converting string commands to Qt signals. - - This is intended for the separation in frontend/backend, this will - live in the frontend. + Signaling server subclass, used to defines the API signals. """ + backend_bad_call = QtCore.Signal(object) - #################### - # These will only exist in the frontend - # Signals for the ProviderBootstrapper - prov_name_resolution = QtCore.Signal(object) - prov_https_connection = QtCore.Signal(object) - prov_download_provider_info = QtCore.Signal(object) - - prov_download_ca_cert = QtCore.Signal(object) - prov_check_ca_fingerprint = QtCore.Signal(object) - prov_check_api_certificate = QtCore.Signal(object) - - prov_problem_with_provider = QtCore.Signal(object) - - prov_unsupported_client = QtCore.Signal(object) - prov_unsupported_api = QtCore.Signal(object) - - prov_get_all_services = QtCore.Signal(object) - prov_get_supported_services = QtCore.Signal(object) - prov_get_details = QtCore.Signal(object) - prov_get_pinned_providers = QtCore.Signal(object) - - prov_cancelled_setup = QtCore.Signal(object) - - # Signals for SRPRegister - srp_registration_finished = QtCore.Signal(object) - srp_registration_failed = QtCore.Signal(object) - srp_registration_taken = QtCore.Signal(object) - - # Signals for EIP bootstrapping - eip_config_ready = QtCore.Signal(object) + eip_alien_openvpn_already_running = QtCore.Signal() + eip_can_start = QtCore.Signal() + eip_cancelled_setup = QtCore.Signal() + eip_cannot_start = QtCore.Signal() eip_client_certificate_ready = QtCore.Signal(object) - - eip_cancelled_setup = QtCore.Signal(object) - - # Signals for SRPAuth - srp_auth_ok = QtCore.Signal(object) - srp_auth_error = QtCore.Signal(object) - srp_auth_server_error = QtCore.Signal(object) - srp_auth_connection_error = QtCore.Signal(object) - srp_auth_bad_user_or_password = QtCore.Signal(object) - srp_logout_ok = QtCore.Signal(object) - srp_logout_error = QtCore.Signal(object) - srp_password_change_ok = QtCore.Signal(object) - srp_password_change_error = QtCore.Signal(object) - srp_password_change_badpw = QtCore.Signal(object) - srp_not_logged_in_error = QtCore.Signal(object) - srp_status_logged_in = QtCore.Signal(object) - srp_status_not_logged_in = QtCore.Signal(object) - - # Signals for EIP - eip_connected = QtCore.Signal(object) - eip_disconnected = QtCore.Signal(object) + eip_config_ready = QtCore.Signal(object) + eip_connected = QtCore.Signal() + eip_connection_aborted = QtCore.Signal() eip_connection_died = QtCore.Signal(object) - eip_connection_aborted = QtCore.Signal(object) - eip_stopped = QtCore.Signal(object) - - eip_dns_ok = QtCore.Signal(object) - eip_dns_error = QtCore.Signal(object) - - # EIP problems - eip_no_polkit_agent_error = QtCore.Signal(object) - eip_no_tun_kext_error = QtCore.Signal(object) - eip_no_pkexec_error = QtCore.Signal(object) - eip_openvpn_not_found_error = QtCore.Signal(object) - eip_openvpn_already_running = QtCore.Signal(object) - eip_alien_openvpn_already_running = QtCore.Signal(object) - eip_vpn_launcher_exception = QtCore.Signal(object) - + eip_disconnected = QtCore.Signal(object) + eip_dns_error = QtCore.Signal() + eip_dns_ok = QtCore.Signal() eip_get_gateways_list = QtCore.Signal(object) - eip_get_gateways_list_error = QtCore.Signal(object) - eip_uninitialized_provider = QtCore.Signal(object) + eip_get_gateways_list_error = QtCore.Signal() eip_get_initialized_providers = QtCore.Signal(object) - - # signals from parsing openvpn output - eip_network_unreachable = QtCore.Signal(object) - eip_process_restart_tls = QtCore.Signal(object) - eip_process_restart_ping = QtCore.Signal(object) - - # signals from vpnprocess.py + eip_network_unreachable = QtCore.Signal() + eip_no_pkexec_error = QtCore.Signal() + eip_no_polkit_agent_error = QtCore.Signal() + eip_no_tun_kext_error = QtCore.Signal() + eip_openvpn_already_running = QtCore.Signal() + eip_openvpn_not_found_error = QtCore.Signal() + eip_process_finished = QtCore.Signal(int) + eip_process_restart_ping = QtCore.Signal() + eip_process_restart_tls = QtCore.Signal() eip_state_changed = QtCore.Signal(dict) eip_status_changed = QtCore.Signal(dict) - eip_process_finished = QtCore.Signal(int) + eip_stopped = QtCore.Signal() eip_tear_fw_down = QtCore.Signal(object) - - # signals whether the needed files to start EIP exist or not - eip_can_start = QtCore.Signal(object) - eip_cannot_start = QtCore.Signal(object) - - # Signals for Soledad - soledad_bootstrap_failed = QtCore.Signal(object) - soledad_bootstrap_finished = QtCore.Signal(object) - soledad_offline_failed = QtCore.Signal(object) - soledad_offline_finished = QtCore.Signal(object) - soledad_invalid_auth_token = QtCore.Signal(object) - soledad_cancelled_bootstrap = QtCore.Signal(object) - soledad_password_change_ok = QtCore.Signal(object) - soledad_password_change_error = QtCore.Signal(object) - - # Keymanager signals - keymanager_export_ok = QtCore.Signal(object) - keymanager_export_error = QtCore.Signal(object) - keymanager_keys_list = QtCore.Signal(object) - - keymanager_import_ioerror = QtCore.Signal(object) - keymanager_import_datamismatch = QtCore.Signal(object) - keymanager_import_missingkey = QtCore.Signal(object) - keymanager_import_addressmismatch = QtCore.Signal(object) - keymanager_import_ok = QtCore.Signal(object) - + eip_uninitialized_provider = QtCore.Signal() + eip_vpn_launcher_exception = QtCore.Signal() + + imap_stopped = QtCore.Signal() + + keymanager_export_error = QtCore.Signal() + keymanager_export_ok = QtCore.Signal() + keymanager_import_addressmismatch = QtCore.Signal() + keymanager_import_datamismatch = QtCore.Signal() + keymanager_import_ioerror = QtCore.Signal() + keymanager_import_missingkey = QtCore.Signal() + keymanager_import_ok = QtCore.Signal() keymanager_key_details = QtCore.Signal(object) + keymanager_keys_list = QtCore.Signal(object) - # mail related signals - imap_stopped = QtCore.Signal(object) - - # This signal is used to warn the backend user that is doing something - # wrong - backend_bad_call = QtCore.Signal(object) - - #################### - # These will exist both in the backend AND the front end. - # The frontend might choose to not "interpret" all the signals - # from the backend, but the backend needs to have all the signals - # it's going to emit defined here - PROV_NAME_RESOLUTION_KEY = "prov_name_resolution" - PROV_HTTPS_CONNECTION_KEY = "prov_https_connection" - PROV_DOWNLOAD_PROVIDER_INFO_KEY = "prov_download_provider_info" - PROV_DOWNLOAD_CA_CERT_KEY = "prov_download_ca_cert" - PROV_CHECK_CA_FINGERPRINT_KEY = "prov_check_ca_fingerprint" - PROV_CHECK_API_CERTIFICATE_KEY = "prov_check_api_certificate" - PROV_PROBLEM_WITH_PROVIDER_KEY = "prov_problem_with_provider" - PROV_UNSUPPORTED_CLIENT = "prov_unsupported_client" - PROV_UNSUPPORTED_API = "prov_unsupported_api" - PROV_CANCELLED_SETUP = "prov_cancelled_setup" - PROV_GET_ALL_SERVICES = "prov_get_all_services" - PROV_GET_SUPPORTED_SERVICES = "prov_get_supported_services" - PROV_GET_DETAILS = "prov_get_details" - PROV_GET_PINNED_PROVIDERS = "prov_get_pinned_providers" - - SRP_REGISTRATION_FINISHED = "srp_registration_finished" - SRP_REGISTRATION_FAILED = "srp_registration_failed" - SRP_REGISTRATION_TAKEN = "srp_registration_taken" - SRP_AUTH_OK = "srp_auth_ok" - SRP_AUTH_ERROR = "srp_auth_error" - SRP_AUTH_SERVER_ERROR = "srp_auth_server_error" - SRP_AUTH_CONNECTION_ERROR = "srp_auth_connection_error" - SRP_AUTH_BAD_USER_OR_PASSWORD = "srp_auth_bad_user_or_password" - SRP_LOGOUT_OK = "srp_logout_ok" - SRP_LOGOUT_ERROR = "srp_logout_error" - SRP_PASSWORD_CHANGE_OK = "srp_password_change_ok" - SRP_PASSWORD_CHANGE_ERROR = "srp_password_change_error" - SRP_PASSWORD_CHANGE_BADPW = "srp_password_change_badpw" - SRP_NOT_LOGGED_IN_ERROR = "srp_not_logged_in_error" - SRP_STATUS_LOGGED_IN = "srp_status_logged_in" - SRP_STATUS_NOT_LOGGED_IN = "srp_status_not_logged_in" - - EIP_CONFIG_READY = "eip_config_ready" - EIP_CLIENT_CERTIFICATE_READY = "eip_client_certificate_ready" - EIP_CANCELLED_SETUP = "eip_cancelled_setup" - - EIP_CONNECTED = "eip_connected" - EIP_DISCONNECTED = "eip_disconnected" - EIP_CONNECTION_DIED = "eip_connection_died" - EIP_CONNECTION_ABORTED = "eip_connection_aborted" - EIP_STOPPED = "eip_stopped" - - EIP_NO_POLKIT_AGENT_ERROR = "eip_no_polkit_agent_error" - EIP_NO_TUN_KEXT_ERROR = "eip_no_tun_kext_error" - EIP_NO_PKEXEC_ERROR = "eip_no_pkexec_error" - EIP_OPENVPN_NOT_FOUND_ERROR = "eip_openvpn_not_found_error" - EIP_OPENVPN_ALREADY_RUNNING = "eip_openvpn_already_running" - EIP_ALIEN_OPENVPN_ALREADY_RUNNING = "eip_alien_openvpn_already_running" - EIP_VPN_LAUNCHER_EXCEPTION = "eip_vpn_launcher_exception" - - EIP_GET_GATEWAYS_LIST = "eip_get_gateways_list" - EIP_GET_GATEWAYS_LIST_ERROR = "eip_get_gateways_list_error" - EIP_UNINITIALIZED_PROVIDER = "eip_uninitialized_provider" - EIP_GET_INITIALIZED_PROVIDERS = "eip_get_initialized_providers" - - EIP_NETWORK_UNREACHABLE = "eip_network_unreachable" - EIP_PROCESS_RESTART_TLS = "eip_process_restart_tls" - EIP_PROCESS_RESTART_PING = "eip_process_restart_ping" - - EIP_STATE_CHANGED = "eip_state_changed" - EIP_STATUS_CHANGED = "eip_status_changed" - EIP_PROCESS_FINISHED = "eip_process_finished" - EIP_TEAR_FW_DOWN = "eip_tear_fw_down" - - EIP_CAN_START = "eip_can_start" - EIP_CANNOT_START = "eip_cannot_start" - - EIP_DNS_OK = "eip_dns_ok" - EIP_DNS_ERROR = "eip_dns_error" - - SOLEDAD_BOOTSTRAP_FAILED = "soledad_bootstrap_failed" - SOLEDAD_BOOTSTRAP_FINISHED = "soledad_bootstrap_finished" - SOLEDAD_OFFLINE_FAILED = "soledad_offline_failed" - SOLEDAD_OFFLINE_FINISHED = "soledad_offline_finished" - SOLEDAD_INVALID_AUTH_TOKEN = "soledad_invalid_auth_token" - - SOLEDAD_PASSWORD_CHANGE_OK = "soledad_password_change_ok" - SOLEDAD_PASSWORD_CHANGE_ERROR = "soledad_password_change_error" - - SOLEDAD_CANCELLED_BOOTSTRAP = "soledad_cancelled_bootstrap" - - KEYMANAGER_EXPORT_OK = "keymanager_export_ok" - KEYMANAGER_EXPORT_ERROR = "keymanager_export_error" - KEYMANAGER_KEYS_LIST = "keymanager_keys_list" - - KEYMANAGER_IMPORT_IOERROR = "keymanager_import_ioerror" - KEYMANAGER_IMPORT_DATAMISMATCH = "keymanager_import_datamismatch" - KEYMANAGER_IMPORT_MISSINGKEY = "keymanager_import_missingkey" - KEYMANAGER_IMPORT_ADDRESSMISMATCH = "keymanager_import_addressmismatch" - KEYMANAGER_IMPORT_OK = "keymanager_import_ok" - KEYMANAGER_KEY_DETAILS = "keymanager_key_details" - - IMAP_STOPPED = "imap_stopped" - - BACKEND_BAD_CALL = "backend_bad_call" - - def __init__(self): - """ - Constructor for the Signaler - """ - QtCore.QObject.__init__(self) - self._signals = {} - - signals = [ - self.PROV_NAME_RESOLUTION_KEY, - self.PROV_HTTPS_CONNECTION_KEY, - self.PROV_DOWNLOAD_PROVIDER_INFO_KEY, - self.PROV_DOWNLOAD_CA_CERT_KEY, - self.PROV_CHECK_CA_FINGERPRINT_KEY, - self.PROV_CHECK_API_CERTIFICATE_KEY, - self.PROV_PROBLEM_WITH_PROVIDER_KEY, - self.PROV_UNSUPPORTED_CLIENT, - self.PROV_UNSUPPORTED_API, - self.PROV_CANCELLED_SETUP, - self.PROV_GET_ALL_SERVICES, - self.PROV_GET_SUPPORTED_SERVICES, - self.PROV_GET_DETAILS, - self.PROV_GET_PINNED_PROVIDERS, - - self.SRP_REGISTRATION_FINISHED, - self.SRP_REGISTRATION_FAILED, - self.SRP_REGISTRATION_TAKEN, - - self.EIP_CONFIG_READY, - self.EIP_CLIENT_CERTIFICATE_READY, - self.EIP_CANCELLED_SETUP, - - self.EIP_CONNECTED, - self.EIP_DISCONNECTED, - self.EIP_CONNECTION_DIED, - self.EIP_CONNECTION_ABORTED, - self.EIP_STOPPED, - - self.EIP_NO_POLKIT_AGENT_ERROR, - self.EIP_NO_TUN_KEXT_ERROR, - self.EIP_NO_PKEXEC_ERROR, - self.EIP_OPENVPN_NOT_FOUND_ERROR, - self.EIP_OPENVPN_ALREADY_RUNNING, - self.EIP_ALIEN_OPENVPN_ALREADY_RUNNING, - self.EIP_VPN_LAUNCHER_EXCEPTION, - - self.EIP_GET_GATEWAYS_LIST, - self.EIP_GET_GATEWAYS_LIST_ERROR, - self.EIP_UNINITIALIZED_PROVIDER, - self.EIP_GET_INITIALIZED_PROVIDERS, - - self.EIP_NETWORK_UNREACHABLE, - self.EIP_PROCESS_RESTART_TLS, - self.EIP_PROCESS_RESTART_PING, - - self.EIP_STATE_CHANGED, - self.EIP_STATUS_CHANGED, - self.EIP_PROCESS_FINISHED, - - self.EIP_CAN_START, - self.EIP_CANNOT_START, - - self.EIP_DNS_OK, - self.EIP_DNS_ERROR, - - self.SRP_AUTH_OK, - self.SRP_AUTH_ERROR, - self.SRP_AUTH_SERVER_ERROR, - self.SRP_AUTH_CONNECTION_ERROR, - self.SRP_AUTH_BAD_USER_OR_PASSWORD, - self.SRP_LOGOUT_OK, - self.SRP_LOGOUT_ERROR, - self.SRP_PASSWORD_CHANGE_OK, - self.SRP_PASSWORD_CHANGE_ERROR, - self.SRP_PASSWORD_CHANGE_BADPW, - self.SRP_NOT_LOGGED_IN_ERROR, - self.SRP_STATUS_LOGGED_IN, - self.SRP_STATUS_NOT_LOGGED_IN, - - self.SOLEDAD_BOOTSTRAP_FAILED, - self.SOLEDAD_BOOTSTRAP_FINISHED, - self.SOLEDAD_OFFLINE_FAILED, - self.SOLEDAD_OFFLINE_FINISHED, - self.SOLEDAD_INVALID_AUTH_TOKEN, - self.SOLEDAD_CANCELLED_BOOTSTRAP, - - self.SOLEDAD_PASSWORD_CHANGE_OK, - self.SOLEDAD_PASSWORD_CHANGE_ERROR, - - self.KEYMANAGER_EXPORT_OK, - self.KEYMANAGER_EXPORT_ERROR, - self.KEYMANAGER_KEYS_LIST, - - self.KEYMANAGER_IMPORT_IOERROR, - self.KEYMANAGER_IMPORT_DATAMISMATCH, - self.KEYMANAGER_IMPORT_MISSINGKEY, - self.KEYMANAGER_IMPORT_ADDRESSMISMATCH, - self.KEYMANAGER_IMPORT_OK, - self.KEYMANAGER_KEY_DETAILS, - - self.IMAP_STOPPED, - - self.BACKEND_BAD_CALL, - ] - - for sig in signals: - self._signals[sig] = getattr(self, sig) - - def signal(self, key, data=None): - """ - Emits a Qt signal based on the key provided, with the data if provided. - - :param key: string identifying the signal to emit - :type key: str - :param data: object to send with the data - :type data: object - - NOTE: The data object will be a serialized str in the backend, - and an unserialized object in the frontend, but for now we - just care about objects. - """ - # Right now it emits Qt signals. The backend version of this - # will do zmq.send_multipart, and the frontend version will be - # similar to this - - # for some reason emitting 'None' gives a segmentation fault. - if data is None: - data = '' - - try: - self._signals[key].emit(data) - except KeyError: - logger.error("Unknown key for signal %s!" % (key,)) + prov_cancelled_setup = QtCore.Signal() + prov_check_api_certificate = QtCore.Signal(object) + prov_check_ca_fingerprint = QtCore.Signal(object) + prov_download_ca_cert = QtCore.Signal(object) + prov_download_provider_info = QtCore.Signal(object) + prov_get_all_services = QtCore.Signal(object) + prov_get_details = QtCore.Signal(object) + prov_get_pinned_providers = QtCore.Signal(object) + prov_get_supported_services = QtCore.Signal(object) + prov_https_connection = QtCore.Signal(object) + prov_name_resolution = QtCore.Signal(object) + prov_problem_with_provider = QtCore.Signal() + prov_unsupported_api = QtCore.Signal() + prov_unsupported_client = QtCore.Signal() + + soledad_bootstrap_failed = QtCore.Signal() + soledad_bootstrap_finished = QtCore.Signal() + soledad_cancelled_bootstrap = QtCore.Signal() + soledad_invalid_auth_token = QtCore.Signal() + soledad_offline_failed = QtCore.Signal() + soledad_offline_finished = QtCore.Signal() + soledad_password_change_error = QtCore.Signal() + soledad_password_change_ok = QtCore.Signal() + + srp_auth_bad_user_or_password = QtCore.Signal() + srp_auth_connection_error = QtCore.Signal() + srp_auth_error = QtCore.Signal() + srp_auth_ok = QtCore.Signal() + srp_auth_server_error = QtCore.Signal() + srp_logout_error = QtCore.Signal() + srp_logout_ok = QtCore.Signal() + srp_not_logged_in_error = QtCore.Signal() + srp_password_change_badpw = QtCore.Signal() + srp_password_change_error = QtCore.Signal() + srp_password_change_ok = QtCore.Signal() + srp_registration_failed = QtCore.Signal() + srp_registration_finished = QtCore.Signal() + srp_registration_taken = QtCore.Signal() + srp_status_logged_in = QtCore.Signal() + srp_status_not_logged_in = QtCore.Signal() -- cgit v1.2.3 From 6dbd52e2f0d75ad9bf7c2f11e3384d8bab0520c9 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 18 Jun 2014 12:37:23 -0300 Subject: Use new backend/signaler and start logic in processes. --- src/leap/bitmask/app.py | 15 +++++++-- src/leap/bitmask/frontend_app.py | 5 +-- src/leap/bitmask/gui/eip_preferenceswindow.py | 5 +-- src/leap/bitmask/gui/eip_status.py | 6 ++-- src/leap/bitmask/gui/mainwindow.py | 45 ++++++++++++++------------- src/leap/bitmask/gui/preferenceswindow.py | 6 ++-- src/leap/bitmask/gui/wizard.py | 10 +++--- src/leap/bitmask/services/eip/conductor.py | 5 +-- 8 files changed, 54 insertions(+), 43 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index f1d87d18..9afe41be 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -43,9 +43,12 @@ import multiprocessing import os import sys +from leap.bitmask.backend.utils import generate_certificates + from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags from leap.bitmask.frontend_app import run_frontend +from leap.bitmask.backend.leapbackend import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber @@ -114,7 +117,6 @@ def start_app(): do_display_version(opts) options = { - 'bypass_checks': opts.danger, 'start_hidden': opts.start_hidden, 'debug': opts.debug, 'log_file': opts.log_file, @@ -170,8 +172,15 @@ def start_app(): logger.info('Starting app') - frontend = multiprocessing.Process(target=run_frontend, args=(options, )) - frontend.start() + generate_certificates() + + app = lambda: run_frontend(options=options) + gui_process = multiprocessing.Process(target=app) + gui_process.start() + + backend = lambda: run_backend(bypass_checks=opts.danger) + backend_process = multiprocessing.Process(target=backend) + backend_process.start() if __name__ == "__main__": diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index ed67a77a..12703518 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -25,7 +25,6 @@ from PySide import QtCore, QtGui from leap.bitmask.config import flags from leap.bitmask.gui import locale_rc # noqa - silence pylint from leap.bitmask.gui.mainwindow import MainWindow -# from leap.bitmask.logs.utils import create_logger import logging logger = logging.getLogger(__name__) @@ -61,7 +60,6 @@ def run_frontend(options): :param options: a dict of options parsed from the command line. :type options: dict """ - bypass_checks = options["bypass_checks"] start_hidden = options["start_hidden"] # We force the style if on KDE so that it doesn't load all the kde @@ -90,8 +88,7 @@ def run_frontend(options): qApp.setApplicationName("leap") qApp.setOrganizationDomain("leap.se") - window = MainWindow(bypass_checks=bypass_checks, - start_hidden=start_hidden) + window = MainWindow(start_hidden=start_hidden) sigint_window = partial(sigint_handler, window, logger=logger) signal.signal(signal.SIGINT, sigint_window) diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py index 530cd38d..caf663b1 100644 --- a/src/leap/bitmask/gui/eip_preferenceswindow.py +++ b/src/leap/bitmask/gui/eip_preferenceswindow.py @@ -33,7 +33,7 @@ class EIPPreferencesWindow(QtGui.QDialog): """ Window that displays the EIP preferences. """ - def __init__(self, parent, domain, backend): + def __init__(self, parent, domain, backend, leap_signaler): """ :param parent: parent object of the EIPPreferencesWindow. :type parent: QWidget @@ -46,6 +46,7 @@ class EIPPreferencesWindow(QtGui.QDialog): self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._settings = LeapSettings() + self._leap_signaler = leap_signaler self._backend = backend # Load UI @@ -248,7 +249,7 @@ class EIPPreferencesWindow(QtGui.QDialog): self.ui.cbGateways.setEnabled(False) def _backend_connect(self): - sig = self._backend.signaler + sig = self._leap_signaler sig.eip_get_gateways_list.connect(self._update_gateways_list) sig.eip_get_gateways_list_error.connect(self._gateways_list_error) sig.eip_uninitialized_provider.connect( diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index bd569343..01966d82 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -44,7 +44,7 @@ class EIPStatusWidget(QtGui.QWidget): RATE_STR = "%1.2f KB/s" TOTAL_STR = "%1.2f Kb" - def __init__(self, parent=None, eip_conductor=None): + def __init__(self, parent, eip_conductor, leap_signaler): """ :param parent: the parent of the widget. :type parent: QObject @@ -60,6 +60,8 @@ class EIPStatusWidget(QtGui.QWidget): self.ui = Ui_EIPStatus() self.ui.setupUi(self) + self._leap_signaler = leap_signaler + self.eip_conductor = eip_conductor self.eipconnection = eip_conductor.eip_connection @@ -98,7 +100,7 @@ class EIPStatusWidget(QtGui.QWidget): """ Connect backend signals. """ - signaler = self.eip_conductor._backend.signaler + signaler = self._leap_signaler signaler.eip_openvpn_already_running.connect( self._on_eip_openvpn_already_running) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index e53ab7f3..4b5d1c83 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -43,7 +43,8 @@ from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform from leap.bitmask.platform_init.initializers import init_signals -from leap.bitmask.backend import leapbackend +from leap.bitmask.backend.backend_proxy import BackendProxy +from leap.bitmask.backend.leapsignaler import LeapSignaler from leap.bitmask.services.eip import conductor as eip_conductor from leap.bitmask.services.mail import conductor as mail_conductor @@ -91,13 +92,10 @@ class MainWindow(QtGui.QMainWindow): # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 20000 # in milliseconds - def __init__(self, bypass_checks=False, start_hidden=False): + def __init__(self, start_hidden=False): """ Constructor for the client main window - :param bypass_checks: Set to true if the app should bypass first round - of checks for CA certificates at bootstrap - :type bypass_checks: bool :param start_hidden: Set to true if the app should not show the window but just the tray. :type start_hidden: bool @@ -119,15 +117,16 @@ class MainWindow(QtGui.QMainWindow): self.ui = Ui_MainWindow() self.ui.setupUi(self) self.menuBar().setNativeMenuBar(not IS_LINUX) - self._backend = leapbackend.Backend(bypass_checks) - self._backend.start() + + self._backend = BackendProxy() + + self._leap_signaler = LeapSignaler() + self._leap_signaler.start() self._settings = LeapSettings() # Login Widget - self._login_widget = LoginWidget( - self._settings, - self) + self._login_widget = LoginWidget(self._settings, self) self.ui.loginLayout.addWidget(self._login_widget) # Mail Widget @@ -144,8 +143,9 @@ class MainWindow(QtGui.QMainWindow): # EIP Control redux ######################################### self._eip_conductor = eip_conductor.EIPConductor( - self._settings, self._backend) - self._eip_status = EIPStatusWidget(self, self._eip_conductor) + self._settings, self._backend, self._leap_signaler) + self._eip_status = EIPStatusWidget(self, self._eip_conductor, + self._leap_signaler) init_signals.eip_missing_helpers.connect( self._disable_eip_missing_helpers) @@ -258,7 +258,6 @@ class MainWindow(QtGui.QMainWindow): self._logger_window = None - self._bypass_checks = bypass_checks self._start_hidden = start_hidden self._mail_conductor = mail_conductor.MailConductor(self._backend) @@ -283,7 +282,7 @@ class MainWindow(QtGui.QMainWindow): self._wizard_firstrun = True self._disconnect_and_untrack() self._wizard = Wizard(backend=self._backend, - bypass_checks=bypass_checks) + leap_signaler=self._leap_signaler) # Give this window time to finish init and then show the wizard QtDelayedCall(1, self._launch_wizard) self._wizard.accepted.connect(self._finish_init) @@ -342,7 +341,7 @@ class MainWindow(QtGui.QMainWindow): that we are tracking to disconnect later. :type only_tracked: bool """ - sig = self._backend.signaler + sig = self._leap_signaler conntrack = self._connect_and_track auth_err = self._authentication_error @@ -480,7 +479,7 @@ class MainWindow(QtGui.QMainWindow): if self._wizard is None: self._disconnect_and_untrack() self._wizard = Wizard(backend=self._backend, - bypass_checks=self._bypass_checks) + leap_signaler=self._leap_signaler) self._wizard.accepted.connect(self._finish_init) self._wizard.rejected.connect(self._rejected_wizard) @@ -575,7 +574,8 @@ class MainWindow(QtGui.QMainWindow): if self._provider_details is not None: mx_provided = MX_SERVICE in self._provider_details['services'] preferences = PreferencesWindow(self, user, domain, self._backend, - self._soledad_started, mx_provided) + self._soledad_started, mx_provided, + self._leap_signaler) self.soledad_ready.connect(preferences.set_soledad_ready) preferences.show() @@ -686,7 +686,9 @@ class MainWindow(QtGui.QMainWindow): Displays the EIP preferences window. """ domain = self._login_widget.get_selected_provider() - EIPPreferencesWindow(self, domain, self._backend).show() + pref = EIPPreferencesWindow(self, domain, + self._backend, self._leap_signaler) + pref.show() # # updates @@ -1277,7 +1279,7 @@ class MainWindow(QtGui.QMainWindow): if MX_SERVICE in self._enabled_services: btn_enabled = self._login_widget.set_logout_btn_enabled btn_enabled(False) - sig = self._backend.signaler + sig = self._leap_signaler sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True)) sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True)) @@ -1711,10 +1713,10 @@ class MainWindow(QtGui.QMainWindow): self._services_being_stopped = set(('imap', 'eip')) imap_stopped = lambda: self._remove_service('imap') - self._backend.signaler.imap_stopped.connect(imap_stopped) + self._leap_signaler.imap_stopped.connect(imap_stopped) eip_stopped = lambda: self._remove_service('eip') - self._backend.signaler.eip_stopped.connect(eip_stopped) + self._leap_signaler.eip_stopped.connect(eip_stopped) logger.debug('Stopping mail services') self._backend.imap_stop_service() @@ -1804,7 +1806,6 @@ class MainWindow(QtGui.QMainWindow): if IS_WIN: WindowsLock.release_all_locks() - self._backend.stop() self.close() QtDelayedCall(100, twisted_main.quit) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index a3b81d38..8cf8752e 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -38,7 +38,8 @@ class PreferencesWindow(QtGui.QDialog): """ preferences_saved = QtCore.Signal() - def __init__(self, parent, username, domain, backend, soledad_started, mx): + def __init__(self, parent, username, domain, backend, soledad_started, mx, + leap_signaler): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -58,6 +59,7 @@ class PreferencesWindow(QtGui.QDialog): self._username = username self._domain = domain + self._leap_signaler = leap_signaler self._backend = backend self._soledad_started = soledad_started self._mx_provided = mx @@ -423,7 +425,7 @@ class PreferencesWindow(QtGui.QDialog): """ Helper to connect to backend signals """ - sig = self._backend.signaler + sig = self._leap_signaler sig.prov_get_supported_services.connect(self._load_services) diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 4f67958f..79cccc44 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -49,16 +49,12 @@ class Wizard(QtGui.QWizard): REGISTER_USER_PAGE = 4 SERVICES_PAGE = 5 - def __init__(self, backend, bypass_checks=False): + def __init__(self, backend, leap_signaler): """ Constructor for the main Wizard. :param backend: Backend being used :type backend: Backend - :param bypass_checks: Set to true if the app should bypass - first round of checks for CA - certificates at bootstrap - :type bypass_checks: bool """ QtGui.QWizard.__init__(self) @@ -86,6 +82,8 @@ class Wizard(QtGui.QWizard): self._connect_and_track(self.ui.lnProvider.returnPressed, self._check_provider) + self._leap_signaler = leap_signaler + self._backend = backend self._backend_connect() @@ -789,7 +787,7 @@ class Wizard(QtGui.QWizard): """ Connects all the backend signals with the wizard. """ - sig = self._backend.signaler + sig = self._leap_signaler conntrack = self._connect_and_track conntrack(sig.prov_name_resolution, self._name_resolution) conntrack(sig.prov_https_connection, self._https_connection) diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index a8821160..dfd27f3d 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -33,7 +33,7 @@ logger = logging.getLogger(__name__) class EIPConductor(object): - def __init__(self, settings, backend, **kwargs): + def __init__(self, settings, backend, leap_signaler, **kwargs): """ Initializes EIP Conductor. @@ -46,6 +46,7 @@ class EIPConductor(object): self.eip_connection = EIPConnection() self.eip_name = get_service_display_name(EIP_SERVICE) self._settings = settings + self._leap_signaler = leap_signaler self._backend = backend self._eip_status = None @@ -76,7 +77,7 @@ class EIPConductor(object): """ Connect to backend signals. """ - signaler = self._backend.signaler + signaler = self._leap_signaler # for conductor signaler.eip_process_restart_tls.connect(self._do_eip_restart) -- cgit v1.2.3 From 5b34d32682188f4849a1e2a4aa8cf8b4c900b8d8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 25 Jun 2014 12:35:04 -0300 Subject: Properly stop backend. --- src/leap/bitmask/gui/mainwindow.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 4b5d1c83..9b6dc8bd 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -18,6 +18,7 @@ Main window for Bitmask. """ import logging +import time from datetime import datetime @@ -1788,7 +1789,6 @@ class MainWindow(QtGui.QMainWindow): Final steps to quit the app, starting from here we don't care about running services or user interaction, just quitting. """ - # We can reach here because all the services are stopped or because a # timeout was triggered. Since we want to run this only once, we exit # if this is called twice. @@ -1801,6 +1801,10 @@ class MainWindow(QtGui.QMainWindow): self._backend.soledad_close() logger.debug('Final quit...') + self._leap_signaler.stop() + self._backend.stop() + time.sleep(0.05) # give the thread a little time to finish. + # Remove lockfiles on a clean shutdown. logger.debug('Cleaning pidfiles') if IS_WIN: -- cgit v1.2.3 From b66c1643eeb094a0f54d621ec3bf2c93173b767d Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 11 Jun 2014 15:35:10 -0300 Subject: Lowercase signals names. --- src/leap/bitmask/backend/components.py | 86 +++++++++++----------- src/leap/bitmask/crypto/srpauth.py | 20 ++--- src/leap/bitmask/crypto/srpregister.py | 6 +- src/leap/bitmask/provider/providerbootstrapper.py | 18 ++--- src/leap/bitmask/services/eip/eipbootstrapper.py | 6 +- src/leap/bitmask/services/eip/vpnprocess.py | 14 ++-- .../services/soledad/soledadbootstrapper.py | 16 ++-- 7 files changed, 83 insertions(+), 83 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 19fcf283..5357bed5 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -197,7 +197,7 @@ class Provider(object): else: if self._signaler is not None: self._signaler.signal( - self._signaler.PROV_PROBLEM_WITH_PROVIDER_KEY) + self._signaler.prov_problem_with_provider) logger.error("Could not load provider configuration.") self._login_widget.set_enabled(True) @@ -234,7 +234,7 @@ class Provider(object): services = get_supported(self._get_services(domain)) self._signaler.signal( - self._signaler.PROV_GET_SUPPORTED_SERVICES, services) + self._signaler.prov_get_supported_services, services) def get_all_services(self, providers): """ @@ -253,7 +253,7 @@ class Provider(object): services_all = services_all.union(set(services)) self._signaler.signal( - self._signaler.PROV_GET_ALL_SERVICES, services_all) + self._signaler.prov_get_all_services, list(services_all)) def get_details(self, domain, lang=None): """ @@ -268,7 +268,7 @@ class Provider(object): prov_get_details -> dict """ self._signaler.signal( - self._signaler.PROV_GET_DETAILS, + self._signaler.prov_get_details, self._provider_config.get_light_config(domain, lang)) def get_pinned_providers(self): @@ -279,7 +279,7 @@ class Provider(object): prov_get_pinned_providers -> list of provider domains """ self._signaler.signal( - self._signaler.PROV_GET_PINNED_PROVIDERS, + self._signaler.prov_get_pinned_providers, PinnedProviders.domains()) @@ -324,7 +324,7 @@ class Register(object): partial(srpregister.register_user, username, password)) else: if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED) + self._signaler.signal(self._signaler.srp_registration_failed) logger.error("Could not load provider configuration.") @@ -401,12 +401,12 @@ class EIP(object): if not self._can_start(domain): if self._signaler is not None: - self._signaler.signal(self._signaler.EIP_CONNECTION_ABORTED) + self._signaler.signal(self._signaler.eip_connection_aborted) return if not loaded: if self._signaler is not None: - self._signaler.signal(self._signaler.EIP_CONNECTION_ABORTED) + self._signaler.signal(self._signaler.eip_connection_aborted) logger.error("Tried to start EIP but cannot find any " "available provider!") return @@ -425,28 +425,28 @@ class EIP(object): if not self._provider_config.loaded(): # This means that the user didn't call setup_eip first. - self._signaler.signal(signaler.BACKEND_BAD_CALL, "EIP.start(), " + self._signaler.signal(signaler.backend_bad_call, "EIP.start(), " "no provider loaded") return try: self._start_eip(*args, **kwargs) except vpnprocess.OpenVPNAlreadyRunning: - signaler.signal(signaler.EIP_OPENVPN_ALREADY_RUNNING) + signaler.signal(signaler.eip_openvpn_already_running) except vpnprocess.AlienOpenVPNAlreadyRunning: - signaler.signal(signaler.EIP_ALIEN_OPENVPN_ALREADY_RUNNING) + signaler.signal(signaler.eip_alien_openvpn_already_running) except vpnlauncher.OpenVPNNotFoundException: - signaler.signal(signaler.EIP_OPENVPN_NOT_FOUND_ERROR) + signaler.signal(signaler.eip_openvpn_not_found_error) except vpnlauncher.VPNLauncherException: # TODO: this seems to be used for 'gateway not found' only. # see vpnlauncher.py - signaler.signal(signaler.EIP_VPN_LAUNCHER_EXCEPTION) + signaler.signal(signaler.eip_vpn_launcher_exception) except linuxvpnlauncher.EIPNoPolkitAuthAgentAvailable: - signaler.signal(signaler.EIP_NO_POLKIT_AGENT_ERROR) + signaler.signal(signaler.eip_no_polkit_agent_error) except linuxvpnlauncher.EIPNoPkexecAvailable: - signaler.signal(signaler.EIP_NO_PKEXEC_ERROR) + signaler.signal(signaler.eip_no_pkexec_error) except darwinvpnlauncher.EIPNoTunKextLoaded: - signaler.signal(signaler.EIP_NO_TUN_KEXT_ERROR) + signaler.signal(signaler.eip_no_tun_kext_error) except Exception as e: logger.error("Unexpected problem: {0!r}".format(e)) else: @@ -482,7 +482,7 @@ class EIP(object): while retry <= MAX_FW_WAIT_RETRIES: if self._vpn.is_fw_down(): - self._signaler.signal(self._signaler.EIP_STOPPED) + self._signaler.signal(self._signaler.eip_stopped) return else: #msg = "Firewall is not down yet, waiting... {0} of {1}" @@ -542,7 +542,7 @@ class EIP(object): filtered_domains.append((domain, is_initialized)) if self._signaler is not None: - self._signaler.signal(self._signaler.EIP_GET_INITIALIZED_PROVIDERS, + self._signaler.signal(self._signaler.eip_get_initialized_providers, filtered_domains) def tear_fw_down(self): @@ -566,7 +566,7 @@ class EIP(object): if not self._provider_is_initialized(domain): if self._signaler is not None: self._signaler.signal( - self._signaler.EIP_UNINITIALIZED_PROVIDER) + self._signaler.eip_uninitialized_provider) return eip_config = eipconfig.EIPConfig() @@ -580,14 +580,14 @@ class EIP(object): if not eip_loaded or provider_config is None: if self._signaler is not None: self._signaler.signal( - self._signaler.EIP_GET_GATEWAYS_LIST_ERROR) + self._signaler.eip_get_gateways_list_error) return gateways = eipconfig.VPNGatewaySelector(eip_config).get_gateways_list() if self._signaler is not None: self._signaler.signal( - self._signaler.EIP_GET_GATEWAYS_LIST, gateways) + self._signaler.eip_get_gateways_list, gateways) def _can_start(self, domain): """ @@ -643,10 +643,10 @@ class EIP(object): """ if self._can_start(domain): if self._signaler is not None: - self._signaler.signal(self._signaler.EIP_CAN_START) + self._signaler.signal(self._signaler.eip_can_start) else: if self._signaler is not None: - self._signaler.signal(self._signaler.EIP_CANNOT_START) + self._signaler.signal(self._signaler.eip_cannot_start) def check_dns(self, domain): """ @@ -665,7 +665,7 @@ class EIP(object): """ Callback handler for `do_check`. """ - self._signaler.signal(self._signaler.EIP_DNS_OK) + self._signaler.signal(self._signaler.eip_dns_ok) logger.debug("DNS check OK") def check_err(failure): @@ -677,7 +677,7 @@ class EIP(object): """ logger.debug("Can't resolve hostname. {0!r}".format(failure)) - self._signaler.signal(self._signaler.EIP_DNS_ERROR) + self._signaler.signal(self._signaler.eip_dns_error) # python 2.7.4 raises socket.error # python 2.7.5 raises socket.gaierror @@ -737,7 +737,7 @@ class Soledad(object): self._soledad_defer.addCallback(self._set_proxies_cb) else: if self._signaler is not None: - self._signaler.signal(self._signaler.SOLEDAD_BOOTSTRAP_FAILED) + self._signaler.signal(self._signaler.soledad_bootstrap_failed) logger.error("Could not load provider configuration.") return self._soledad_defer @@ -793,7 +793,7 @@ class Soledad(object): Password change callback. """ if self._signaler is not None: - self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_OK) + self._signaler.signal(self._signaler.soledad_password_change_ok) def _change_password_error(self, failure): """ @@ -808,7 +808,7 @@ class Soledad(object): logger.error("Passphrase too short.") if self._signaler is not None: - self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_ERROR) + self._signaler.signal(self._signaler.soledad_password_change_error) def change_password(self, new_password): """ @@ -866,7 +866,7 @@ class Keymanager(object): new_key = keys_file.read() except IOError as e: logger.error("IOError importing key. {0!r}".format(e)) - signal = self._signaler.KEYMANAGER_IMPORT_IOERROR + signal = self._signaler.keymanager_import_ioerror self._signaler.signal(signal) return @@ -876,19 +876,19 @@ class Keymanager(object): new_key) except (KeyAddressMismatch, KeyFingerprintMismatch) as e: logger.error(repr(e)) - signal = self._signaler.KEYMANAGER_IMPORT_DATAMISMATCH + signal = self._signaler.keymanager_import_datamismatch self._signaler.signal(signal) return if public_key is None or private_key is None: - signal = self._signaler.KEYMANAGER_IMPORT_MISSINGKEY + signal = self._signaler.keymanager_import_missingkey self._signaler.signal(signal) return current_public_key = keymanager.get_key(username, openpgp.OpenPGPKey) if public_key.address != current_public_key.address: logger.error("The key does not match the ID") - signal = self._signaler.KEYMANAGER_IMPORT_ADDRESSMISMATCH + signal = self._signaler.keymanager_import_addressmismatch self._signaler.signal(signal) return @@ -899,7 +899,7 @@ class Keymanager(object): keymanager.send_key(openpgp.OpenPGPKey) logger.debug('Import ok') - signal = self._signaler.KEYMANAGER_IMPORT_OK + signal = self._signaler.keymanager_import_ok self._signaler.signal(signal) @@ -923,17 +923,17 @@ class Keymanager(object): keys_file.write(private_key.key_data) logger.debug('Export ok') - self._signaler.signal(self._signaler.KEYMANAGER_EXPORT_OK) + self._signaler.signal(self._signaler.keymanager_export_ok) except IOError as e: logger.error("IOError exporting key. {0!r}".format(e)) - self._signaler.signal(self._signaler.KEYMANAGER_EXPORT_ERROR) + self._signaler.signal(self._signaler.keymanager_export_error) def list_keys(self): """ List all the keys stored in the local DB. """ keys = self._keymanager_proxy.get_all_keys_in_local_db() - self._signaler.signal(self._signaler.KEYMANAGER_KEYS_LIST, keys) + self._signaler.signal(self._signaler.keymanager_keys_list, keys) def get_key_details(self, username): """ @@ -942,7 +942,7 @@ class Keymanager(object): public_key = self._keymanager_proxy.get_key(username, openpgp.OpenPGPKey) details = (public_key.key_id, public_key.fingerprint) - self._signaler.signal(self._signaler.KEYMANAGER_KEY_DETAILS, details) + self._signaler.signal(self._signaler.keymanager_key_details, details) class Mail(object): @@ -1027,7 +1027,7 @@ class Mail(object): logger.debug('Waiting for imap service to stop.') cv.wait(self.SERVICE_STOP_TIMEOUT) logger.debug('IMAP stopped') - self._signaler.signal(self._signaler.IMAP_STOPPED) + self._signaler.signal(self._signaler.imap_stopped) def stop_imap_service(self): """ @@ -1080,7 +1080,7 @@ class Authenticate(object): return self._login_defer else: if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_AUTH_ERROR) + self._signaler.signal(self._signaler.srp_auth_error) logger.error("Could not load provider configuration.") def cancel_login(self): @@ -1105,7 +1105,7 @@ class Authenticate(object): """ if not self._is_logged_in(): if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR) + self._signaler.signal(self._signaler.srp_not_logged_in_error) return return self._srp_auth.change_password(current_password, new_password) @@ -1117,7 +1117,7 @@ class Authenticate(object): """ if not self._is_logged_in(): if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR) + self._signaler.signal(self._signaler.srp_not_logged_in_error) return self._srp_auth.logout() @@ -1140,8 +1140,8 @@ class Authenticate(object): signal = None if self._is_logged_in(): - signal = self._signaler.SRP_STATUS_LOGGED_IN + signal = self._signaler.srp_status_logged_in else: - signal = self._signaler.SRP_STATUS_NOT_LOGGED_IN + signal = self._signaler.srp_status_not_logged_in self._signaler.signal(signal) diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index 192a9d5c..856d2c81 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -523,7 +523,7 @@ class SRPAuth(object): Password change callback. """ if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_OK) + self._signaler.signal(self._signaler.srp_password_change_ok) def _change_password_error(self, failure): """ @@ -535,9 +535,9 @@ class SRPAuth(object): return if failure.check(SRPAuthBadUserOrPassword): - self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_BADPW) + self._signaler.signal(self._signaler.srp_password_change_badpw) else: - self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_ERROR) + self._signaler.signal(self._signaler.srp_password_change_error) def authenticate(self, username, password): """ @@ -591,7 +591,7 @@ class SRPAuth(object): :type _: IGNORED """ logger.debug("Successful login!") - self._signaler.signal(self._signaler.SRP_AUTH_OK) + self._signaler.signal(self._signaler.srp_auth_ok) def _authenticate_error(self, failure): """ @@ -612,13 +612,13 @@ class SRPAuth(object): return if failure.check(SRPAuthBadUserOrPassword): - signal = self._signaler.SRP_AUTH_BAD_USER_OR_PASSWORD + signal = self._signaler.srp_auth_bad_user_or_password elif failure.check(SRPAuthConnectionError): - signal = self._signaler.SRP_AUTH_CONNECTION_ERROR + signal = self._signaler.srp_auth_connection_error elif failure.check(SRPAuthenticationError): - signal = self._signaler.SRP_AUTH_SERVER_ERROR + signal = self._signaler.srp_auth_server_error else: - signal = self._signaler.SRP_AUTH_ERROR + signal = self._signaler.srp_auth_error self._signaler.signal(signal) @@ -647,7 +647,7 @@ class SRPAuth(object): logger.warning("Something went wrong with the logout: %r" % (e,)) if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_LOGOUT_ERROR) + self._signaler.signal(self._signaler.srp_logout_error) raise else: self.set_session_id(None) @@ -657,7 +657,7 @@ class SRPAuth(object): self._session = self._fetcher.session() logger.debug("Successfully logged out.") if self._signaler is not None: - self._signaler.signal(self._signaler.SRP_LOGOUT_OK) + self._signaler.signal(self._signaler.srp_logout_ok) def set_session_id(self, session_id): with self._session_id_lock: diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py index f03dc469..86510de1 100644 --- a/src/leap/bitmask/crypto/srpregister.py +++ b/src/leap/bitmask/crypto/srpregister.py @@ -179,11 +179,11 @@ class SRPRegister(QtCore.QObject): return if status_code in self.STATUS_OK: - self._signaler.signal(self._signaler.SRP_REGISTRATION_FINISHED) + self._signaler.signal(self._signaler.srp_registration_finished) elif status_code == self.STATUS_TAKEN: - self._signaler.signal(self._signaler.SRP_REGISTRATION_TAKEN) + self._signaler.signal(self._signaler.srp_registration_taken) else: - self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED) + self._signaler.signal(self._signaler.srp_registration_failed) if __name__ == "__main__": diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py index 8c96a8b5..5064f6a4 100644 --- a/src/leap/bitmask/provider/providerbootstrapper.py +++ b/src/leap/bitmask/provider/providerbootstrapper.py @@ -90,7 +90,7 @@ class ProviderBootstrapper(AbstractBootstrapper): self._provider_config = None self._download_if_needed = False if signaler is not None: - self._cancel_signal = signaler.PROV_CANCELLED_SETUP + self._cancel_signal = signaler.prov_cancelled_setup @property def verify(self): @@ -228,7 +228,7 @@ class ProviderBootstrapper(AbstractBootstrapper): # TODO split if not provider.supports_client(min_client_version): self._signaler.signal( - self._signaler.PROV_UNSUPPORTED_CLIENT) + self._signaler.prov_unsupported_client) raise UnsupportedClientVersionError() provider_definition, mtime = get_content(res) @@ -250,7 +250,7 @@ class ProviderBootstrapper(AbstractBootstrapper): 'Found: {1}.').format(api_supported, api_version) logger.error(error) - self._signaler.signal(self._signaler.PROV_UNSUPPORTED_API) + self._signaler.signal(self._signaler.prov_unsupported_api) raise UnsupportedProviderAPI(error) def run_provider_select_checks(self, domain, download_if_needed=False): @@ -271,10 +271,10 @@ class ProviderBootstrapper(AbstractBootstrapper): cb_chain = [ (self._check_name_resolution, - self._signaler.PROV_NAME_RESOLUTION_KEY), - (self._check_https, self._signaler.PROV_HTTPS_CONNECTION_KEY), + self._signaler.prov_name_resolution), + (self._check_https, self._signaler.prov_https_connection), (self._download_provider_info, - self._signaler.PROV_DOWNLOAD_PROVIDER_INFO_KEY) + self._signaler.prov_download_provider_info) ] return self.addCallbackChain(cb_chain) @@ -401,11 +401,11 @@ class ProviderBootstrapper(AbstractBootstrapper): self._download_if_needed = download_if_needed cb_chain = [ - (self._download_ca_cert, self._signaler.PROV_DOWNLOAD_CA_CERT_KEY), + (self._download_ca_cert, self._signaler.prov_download_ca_cert), (self._check_ca_fingerprint, - self._signaler.PROV_CHECK_CA_FINGERPRINT_KEY), + self._signaler.prov_check_ca_fingerprint), (self._check_api_certificate, - self._signaler.PROV_CHECK_API_CERTIFICATE_KEY) + self._signaler.prov_check_api_certificate) ] return self.addCallbackChain(cb_chain) diff --git a/src/leap/bitmask/services/eip/eipbootstrapper.py b/src/leap/bitmask/services/eip/eipbootstrapper.py index c77977ce..264eac2e 100644 --- a/src/leap/bitmask/services/eip/eipbootstrapper.py +++ b/src/leap/bitmask/services/eip/eipbootstrapper.py @@ -53,7 +53,7 @@ class EIPBootstrapper(AbstractBootstrapper): self._eip_config = None self._download_if_needed = False if signaler is not None: - self._cancel_signal = signaler.EIP_CANCELLED_SETUP + self._cancel_signal = signaler.eip_cancelled_setup def _download_config(self, *args): """ @@ -116,9 +116,9 @@ class EIPBootstrapper(AbstractBootstrapper): self._download_if_needed = download_if_needed cb_chain = [ - (self._download_config, self._signaler.EIP_CONFIG_READY), + (self._download_config, self._signaler.eip_config_ready), (self._download_client_certificates, - self._signaler.EIP_CLIENT_CERTIFICATE_READY) + self._signaler.eip_client_certificate_ready) ] return self.addCallbackChain(cb_chain) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index b54f2925..3bda3059 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -118,10 +118,10 @@ class VPNObserver(object): """ sig = self._signaler signals = { - "network_unreachable": sig.EIP_NETWORK_UNREACHABLE, - "process_restart_tls": sig.EIP_PROCESS_RESTART_TLS, - "process_restart_ping": sig.EIP_PROCESS_RESTART_PING, - "initialization_completed": sig.EIP_CONNECTED + "network_unreachable": sig.eip_network_unreachable, + "process_restart_tls": sig.eip_process_restart_tls, + "process_restart_ping": sig.eip_process_restart_ping, + "initialization_completed": sig.eip_connected } return signals.get(event.lower()) @@ -594,7 +594,7 @@ class VPNManager(object): state = status_step if state != self._last_state: - self._signaler.signal(self._signaler.EIP_STATE_CHANGED, state) + self._signaler.signal(self._signaler.eip_state_changed, state) self._last_state = state def _parse_status_and_notify(self, output): @@ -632,7 +632,7 @@ class VPNManager(object): status = (tun_tap_read, tun_tap_write) if status != self._last_status: - self._signaler.signal(self._signaler.EIP_STATUS_CHANGED, status) + self._signaler.signal(self._signaler.eip_status_changed, status) self._last_status = status def get_state(self): @@ -869,7 +869,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): if isinstance(exit_code, int): logger.debug("processExited, status %d" % (exit_code,)) self._signaler.signal( - self._signaler.EIP_PROCESS_FINISHED, exit_code) + self._signaler.eip_process_finished, exit_code) self._alive = False def processEnded(self, reason): diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index b9243add..a5904dce 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -141,7 +141,7 @@ class SoledadBootstrapper(AbstractBootstrapper): AbstractBootstrapper.__init__(self, signaler) if signaler is not None: - self._cancel_signal = signaler.SOLEDAD_CANCELLED_BOOTSTRAP + self._cancel_signal = signaler.soledad_cancelled_bootstrap self._provider_config = None self._soledad_config = None @@ -190,11 +190,11 @@ class SoledadBootstrapper(AbstractBootstrapper): self._uuid = uuid try: self.load_and_sync_soledad(uuid, offline=True) - self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FINISHED) + self._signaler.signal(self._signaler.soledad_offline_finished) except Exception as e: # TODO: we should handle more specific exceptions in here logger.exception(e) - self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FAILED) + self._signaler.signal(self._signaler.soledad_offline_failed) def _get_soledad_local_params(self, uuid, offline=False): """ @@ -390,7 +390,7 @@ class SoledadBootstrapper(AbstractBootstrapper): continue except InvalidAuthTokenError: self._signaler.signal( - self._signaler.SOLEDAD_INVALID_AUTH_TOKEN) + self._signaler.soledad_invalid_auth_token) raise except Exception as e: # XXX release syncing lock @@ -649,11 +649,11 @@ class SoledadBootstrapper(AbstractBootstrapper): self._password = password if flags.OFFLINE: - signal_finished = self._signaler.SOLEDAD_OFFLINE_FINISHED - signal_failed = self._signaler.SOLEDAD_OFFLINE_FAILED + signal_finished = self._signaler.soledad_offline_finished + signal_failed = self._signaler.soledad_offline_failed else: - signal_finished = self._signaler.SOLEDAD_BOOTSTRAP_FINISHED - signal_failed = self._signaler.SOLEDAD_BOOTSTRAP_FAILED + signal_finished = self._signaler.soledad_bootstrap_finished + signal_failed = self._signaler.soledad_bootstrap_failed try: self._download_config() -- cgit v1.2.3 From d35f12b00629d6578039a11ce5e18d0c58e3fa73 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 17 Jun 2014 18:42:37 -0300 Subject: Do backend calls using kwargs. --- src/leap/bitmask/gui/eip_preferenceswindow.py | 4 ++-- src/leap/bitmask/gui/mainwindow.py | 27 ++++++++++++++++----------- src/leap/bitmask/gui/preferenceswindow.py | 7 ++++--- src/leap/bitmask/gui/wizard.py | 9 +++++---- src/leap/bitmask/services/mail/conductor.py | 6 ++++-- 5 files changed, 31 insertions(+), 22 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py index caf663b1..306fdb8c 100644 --- a/src/leap/bitmask/gui/eip_preferenceswindow.py +++ b/src/leap/bitmask/gui/eip_preferenceswindow.py @@ -97,7 +97,7 @@ class EIPPreferencesWindow(QtGui.QDialog): if not providers: return - self._backend.eip_get_initialized_providers(providers) + self._backend.eip_get_initialized_providers(domains=providers) @QtCore.Slot(list) def _load_providers_in_combo(self, providers): @@ -175,7 +175,7 @@ class EIPPreferencesWindow(QtGui.QDialog): domain = self.ui.cbProvidersGateway.itemData(domain_idx) self._selected_domain = domain - self._backend.eip_get_gateways_list(domain) + self._backend.eip_get_gateways_list(domain=domain) @QtCore.Slot(list) def _update_gateways_list(self, gateways): diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 9b6dc8bd..24915d4f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -605,12 +605,13 @@ class MainWindow(QtGui.QMainWindow): return self._trying_to_start_eip = settings.get_autostart_eip() - self._backend.eip_can_start(default_provider) + self._backend.eip_can_start(domain=default_provider) # If we don't want to start eip, we leave everything # initialized to quickly start it if not self._trying_to_start_eip: - self._backend.eip_setup(default_provider, skip_network=True) + self._backend.eip_setup(provider=default_provider, + skip_network=True) def _backend_can_start_eip(self): """ @@ -824,7 +825,7 @@ class MainWindow(QtGui.QMainWindow): """ providers = self._settings.get_configured_providers() - self._backend.provider_get_all_services(providers) + self._backend.provider_get_all_services(providers=providers) def _provider_get_all_services(self, services): self._set_eip_visible(EIP_SERVICE in services) @@ -1124,7 +1125,7 @@ class MainWindow(QtGui.QMainWindow): emit the corresponding signals inmediately """ domain = self._login_widget.get_selected_provider() - self._backend.provider_setup(domain) + self._backend.provider_setup(provider=domain) @QtCore.Slot(dict) def _load_provider_config(self, data): @@ -1141,7 +1142,7 @@ class MainWindow(QtGui.QMainWindow): """ if data[self._backend.PASSED_KEY]: selected_provider = self._login_widget.get_selected_provider() - self._backend.provider_bootstrap(selected_provider) + self._backend.provider_bootstrap(provider=selected_provider) else: logger.error(data[self._backend.ERROR_KEY]) self._login_problem_provider() @@ -1252,7 +1253,8 @@ class MainWindow(QtGui.QMainWindow): self._show_hide_unsupported_services() domain = self._login_widget.get_selected_provider() - self._backend.user_login(domain, username, password) + self._backend.user_login(provider=domain, + username=username, password=password) else: logger.error(data[self._backend.ERROR_KEY]) self._login_problem_provider() @@ -1319,7 +1321,7 @@ class MainWindow(QtGui.QMainWindow): """ domain = self._login_widget.get_selected_provider() lang = QtCore.QLocale.system().name() - self._backend.provider_get_details(domain, lang) + self._backend.provider_get_details(domain=domain, lang=lang) @QtCore.Slot() def _provider_get_details(self, details): @@ -1388,11 +1390,14 @@ class MainWindow(QtGui.QMainWindow): # this is mostly for internal use/debug for now. logger.warning("Sorry! Log-in at least one time.") return - self._backend.soledad_load_offline(full_user_id, password, uuid) + self._backend.soledad_load_offline(username=full_user_id, + password=password, uuid=uuid) else: if self._logged_user is not None: domain = self._login_widget.get_selected_provider() - self._backend.soledad_bootstrap(username, domain, password) + self._backend.soledad_bootstrap(username=username, + domain=domain, + password=password) ################################################################### # Service control methods: soledad @@ -1478,7 +1483,7 @@ class MainWindow(QtGui.QMainWindow): self._already_started_eip = True # check for connectivity - self._backend.eip_check_dns(domain) + self._backend.eip_check_dns(domain=domain) @QtCore.Slot() def _eip_dns_error(self): @@ -1542,7 +1547,7 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.eip_button.setEnabled(False) domain = self._login_widget.get_selected_provider() - self._backend.eip_setup(domain) + self._backend.eip_setup(provider=domain) self._already_started_eip = True # we want to start soledad anyway after a certain timeout if eip diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 8cf8752e..3c9cd5d0 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -196,7 +196,8 @@ class PreferencesWindow(QtGui.QDialog): return self._set_changing_password(True) - self._backend.user_change_password(current_password, new_password) + self._backend.user_change_password(current_password=current_password, + new_password=new_password) @QtCore.Slot() def _srp_change_password_ok(self): @@ -210,7 +211,7 @@ class PreferencesWindow(QtGui.QDialog): logger.debug("SRP password changed successfully.") if self._mx_provided: - self._backend.soledad_change_password(new_password) + self._backend.soledad_change_password(new_password=new_password) else: self._change_password_success() @@ -359,7 +360,7 @@ class PreferencesWindow(QtGui.QDialog): save_services = partial(self._save_enabled_services, domain) self.ui.pbSaveServices.clicked.connect(save_services) - self._backend.provider_get_supported_services(domain) + self._backend.provider_get_supported_services(domain=domain) @QtCore.Slot(str) def _load_services(self, services): diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 79cccc44..a20ef9fe 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -323,7 +323,8 @@ class Wizard(QtGui.QWizard): if user_ok and pass_ok: self._set_register_status(self.tr("Starting registration...")) - self._backend.user_register(self._domain, username, password) + self._backend.user_register(provider=self._domain, + username=username, password=password) self._username = username self._password = password else: @@ -475,7 +476,7 @@ class Wizard(QtGui.QWizard): self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON) self._provider_select_defer = self._backend.\ - provider_setup(self._domain) + provider_setup(provider=self._domain) @QtCore.Slot(bool) def _skip_provider_checks(self, skip): @@ -576,7 +577,7 @@ class Wizard(QtGui.QWizard): True, self.SELECT_PROVIDER_PAGE) self._provider_checks_ok = True lang = QtCore.QLocale.system().name() - self._backend.provider_get_details(self._domain, lang) + self._backend.provider_get_details(domain=self._domain, lang=lang) else: new_data = { self._backend.PASSED_KEY: False, @@ -724,7 +725,7 @@ class Wizard(QtGui.QWizard): self.page(pageId).setSubTitle(sub_title) self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) self._provider_setup_defer = self._backend.\ - provider_bootstrap(self._domain) + provider_bootstrap(provider=self._domain) if pageId == self.PRESENT_PROVIDER_PAGE: sub_title = self.tr("Description of services offered by {0}") diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index 98b40929..5e85368f 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -64,7 +64,8 @@ class IMAPControl(object): """ Start imap service. """ - self._backend.imap_start_service(self.userid, flags.OFFLINE) + self._backend.imap_start_service(full_user_id=self.userid, + offline=flags.OFFLINE) def stop_imap_service(self): """ @@ -146,7 +147,8 @@ class SMTPControl(object): :type download_if_needed: bool """ self.smtp_connection.qtsigs.connecting_signal.emit() - self._backend.smtp_start_service(self.userid, download_if_needed) + self._backend.smtp_start_service(full_user_id=self.userid, + download_if_needed=download_if_needed) def stop_smtp_service(self): """ -- cgit v1.2.3 From c46a93e290194cdeb1b4e1776d4bf0edde303072 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 25 Jun 2014 12:36:25 -0300 Subject: Add SIGINT handler. --- src/leap/bitmask/app.py | 4 ++++ src/leap/bitmask/frontend_app.py | 22 +++++----------------- 2 files changed, 9 insertions(+), 17 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 9afe41be..eda4073c 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -41,6 +41,7 @@ # (thanks to: http://www.glassgiant.com/ascii/) import multiprocessing import os +import signal import sys from leap.bitmask.backend.utils import generate_certificates @@ -112,6 +113,9 @@ def start_app(): """ Starts the main event loop and launches the main window. """ + # Ensure that the application quits using CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + # Parse arguments and store them opts = leap_argparse.get_options() do_display_version(opts) diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 12703518..60f20e3c 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -18,8 +18,6 @@ import signal import sys import os -from functools import partial - from PySide import QtCore, QtGui from leap.bitmask.config import flags @@ -41,18 +39,6 @@ def sigint_handler(*args, **kwargs): mainwindow.quit() -def sigterm_handler(*args, **kwargs): - """ - Signal handler for SIGTERM. - This handler is actually passed to twisted reactor - """ - logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGTERM catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() - - def run_frontend(options): """ Run the GUI for the application. @@ -88,10 +74,12 @@ def run_frontend(options): qApp.setApplicationName("leap") qApp.setOrganizationDomain("leap.se") - window = MainWindow(start_hidden=start_hidden) + MainWindow(start_hidden=start_hidden) - sigint_window = partial(sigint_handler, window, logger=logger) - signal.signal(signal.SIGINT, sigint_window) + # sigint_window = partial(sigint_handler, window, logger=logger) + # signal.signal(signal.SIGINT, sigint_window) + # Ensure that the application quits using CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) sys.exit(qApp.exec_()) -- cgit v1.2.3 From 4a5e136f3b6e68d65df4a5be83504e05043aeaa1 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 19 Jun 2014 16:13:42 -0300 Subject: Add missing error/passed keys. --- src/leap/bitmask/backend/leapbackend.py | 3 +++ src/leap/bitmask/gui/mainwindow.py | 25 +++++++++++++++---------- src/leap/bitmask/gui/wizard.py | 27 +++++++++++++++------------ 3 files changed, 33 insertions(+), 22 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index cc7227ad..d6b0954a 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -28,6 +28,9 @@ from leap.bitmask.backend.backend import Backend logger = logging.getLogger(__name__) +ERROR_KEY = "error" +PASSED_KEY = "passed" + class LeapBackend(Backend): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 24915d4f..a77f0215 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -26,6 +26,11 @@ from PySide import QtCore, QtGui from leap.bitmask import __version__ as VERSION from leap.bitmask import __version_hash__ as VERSION_HASH + +# TODO: we should use a more granular signaling instead of passing error/ok as +# a result. +from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY + from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings @@ -1140,11 +1145,11 @@ class MainWindow(QtGui.QMainWindow): backend.provider_setup() :type data: dict """ - if data[self._backend.PASSED_KEY]: + if data[PASSED_KEY]: selected_provider = self._login_widget.get_selected_provider() self._backend.provider_bootstrap(provider=selected_provider) else: - logger.error(data[self._backend.ERROR_KEY]) + logger.error(data[ERROR_KEY]) self._login_problem_provider() @QtCore.Slot() @@ -1246,7 +1251,7 @@ class MainWindow(QtGui.QMainWindow): Once the provider configuration is loaded, this starts the SRP authentication """ - if data[self._backend.PASSED_KEY]: + if data[PASSED_KEY]: username = self._login_widget.get_user() password = self._login_widget.get_password() @@ -1256,7 +1261,7 @@ class MainWindow(QtGui.QMainWindow): self._backend.user_login(provider=domain, username=username, password=password) else: - logger.error(data[self._backend.ERROR_KEY]) + logger.error(data[ERROR_KEY]) self._login_problem_provider() @QtCore.Slot() @@ -1579,12 +1584,12 @@ class MainWindow(QtGui.QMainWindow): Start the VPN thread if the eip configuration is properly loaded. """ - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if not passed: error_msg = self.tr("There was a problem with the provider") self._eip_status.set_eip_status(error_msg, error=True) - logger.error(data[self._backend.ERROR_KEY]) + logger.error(data[ERROR_KEY]) self._already_started_eip = False return @@ -1602,11 +1607,11 @@ class MainWindow(QtGui.QMainWindow): This is used for intermediate bootstrapping stages, in case they fail. """ - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if not passed: self._login_widget.set_status( self.tr("Unable to connect: Problem with provider")) - logger.error(data[self._backend.ERROR_KEY]) + logger.error(data[ERROR_KEY]) self._already_started_eip = False self._eip_status.aborted() @@ -1671,9 +1676,9 @@ class MainWindow(QtGui.QMainWindow): This is used for intermediate bootstrapping stages, in case they fail. """ - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if not passed: - logger.error(data[self._backend.ERROR_KEY]) + logger.error(data[ERROR_KEY]) self._login_problem_provider() # diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index a20ef9fe..be5bde52 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -24,6 +24,10 @@ from functools import partial from PySide import QtCore, QtGui +# TODO: we should use a more granular signaling instead of passing error/ok as +# a result. +from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY + from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.services import get_service_display_name, get_supported @@ -511,8 +515,8 @@ class Wizard(QtGui.QWizard): :param complete_page: page id to complete :type complete_page: int """ - passed = data[self._backend.PASSED_KEY] - error = data[self._backend.ERROR_KEY] + passed = data[PASSED_KEY] + error = data[ERROR_KEY] if passed: label.setPixmap(self.OK_ICON) if complete: @@ -532,7 +536,7 @@ class Wizard(QtGui.QWizard): """ self._complete_task(data, self.ui.lblNameResolution) status = "" - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if not passed: status = self.tr("Non-existent " "provider") @@ -552,10 +556,10 @@ class Wizard(QtGui.QWizard): """ self._complete_task(data, self.ui.lblHTTPS) status = "" - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if not passed: status = self.tr("%s") \ - % (data[self._backend.ERROR_KEY]) + % (data[ERROR_KEY]) self.ui.lblProviderSelectStatus.setText(status) else: self.ui.lblProviderInfo.setPixmap(self.QUESTION_ICON) @@ -572,7 +576,7 @@ class Wizard(QtGui.QWizard): check. Since this check is the last of this set, it also completes the page if passed """ - if data[self._backend.PASSED_KEY]: + if data[PASSED_KEY]: self._complete_task(data, self.ui.lblProviderInfo, True, self.SELECT_PROVIDER_PAGE) self._provider_checks_ok = True @@ -580,14 +584,13 @@ class Wizard(QtGui.QWizard): self._backend.provider_get_details(domain=self._domain, lang=lang) else: new_data = { - self._backend.PASSED_KEY: False, - self._backend.ERROR_KEY: - self.tr("Unable to load provider configuration") + PASSED_KEY: False, + ERROR_KEY: self.tr("Unable to load provider configuration") } self._complete_task(new_data, self.ui.lblProviderInfo) status = "" - if not data[self._backend.PASSED_KEY]: + if not data[PASSED_KEY]: status = self.tr("Not a valid provider" "") self.ui.lblProviderSelectStatus.setText(status) @@ -618,7 +621,7 @@ class Wizard(QtGui.QWizard): Sets the status for the download of the CA certificate check """ self._complete_task(data, self.ui.lblDownloadCaCert) - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if passed: self.ui.lblCheckCaFpr.setPixmap(self.QUESTION_ICON) @@ -631,7 +634,7 @@ class Wizard(QtGui.QWizard): Sets the status for the CA fingerprint check """ self._complete_task(data, self.ui.lblCheckCaFpr) - passed = data[self._backend.PASSED_KEY] + passed = data[PASSED_KEY] if passed: self.ui.lblCheckApiCert.setPixmap(self.QUESTION_ICON) -- cgit v1.2.3 From cf75e3575c33249a6f756dceb423c6ec7f6cd50e Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 12:14:22 -0300 Subject: Move the backend starter to its own file. --- src/leap/bitmask/app.py | 2 +- src/leap/bitmask/backend/leapbackend.py | 9 --------- src/leap/bitmask/backend_app.py | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index eda4073c..43dabad3 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -49,7 +49,7 @@ from leap.bitmask.backend.utils import generate_certificates from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags from leap.bitmask.frontend_app import run_frontend -from leap.bitmask.backend.leapbackend import run_backend +from leap.bitmask.backend_app import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index d6b0954a..4794d988 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -18,7 +18,6 @@ Backend for everything """ import logging -import signal import zope.interface import zope.proxy @@ -503,11 +502,3 @@ class LeapBackend(Backend): imap_stopped """ self._mail.stop_imap_service() - - -def run_backend(bypass_checks=False): - # Ensure that the application quits using CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) - - backend = LeapBackend(bypass_checks=bypass_checks) - backend.run() diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index e69de29b..bd3b8a1f 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# backend_app.py +# Copyright (C) 2013, 2014 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 . +import signal + +from leap.bitmask.backend.leapbackend import LeapBackend + + +def run_backend(bypass_checks=False): + # Ensure that the application quits using CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + + backend = LeapBackend(bypass_checks=bypass_checks) + backend.run() -- cgit v1.2.3 From 13c0b7cac822a33f7395e3f099a2d37251e2c759 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 12:14:59 -0300 Subject: Ask the backend for the country code. Remove global variable in favor of a helper method that returns the country code. Needed in order to split backend/frontend. --- src/leap/bitmask/backend/api.py | 3 ++ src/leap/bitmask/backend/components.py | 42 ++++++++++++++++++++++++++++ src/leap/bitmask/backend/leapbackend.py | 13 +++++++++ src/leap/bitmask/backend/leapsignaler.py | 2 ++ src/leap/bitmask/config/flags.py | 2 -- src/leap/bitmask/gui/eip_status.py | 15 +++++++--- src/leap/bitmask/gui/mainwindow.py | 22 +++++++++++++-- src/leap/bitmask/services/eip/vpnlauncher.py | 6 ---- 8 files changed, 90 insertions(+), 15 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index 012b3cbc..f8b8c699 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -26,6 +26,7 @@ API = ( "eip_can_start", "eip_cancel_setup", "eip_check_dns", + "eip_get_gateway_country_code", "eip_get_gateways_list", "eip_get_initialized_providers", "eip_setup", @@ -75,10 +76,12 @@ SIGNALS = ( "eip_disconnected", "eip_dns_error", "eip_dns_ok", + "eip_get_gateway_country_code", "eip_get_gateways_list", "eip_get_gateways_list_error", "eip_get_initialized_providers", "eip_network_unreachable", + "eip_no_gateway", "eip_no_pkexec_error", "eip_no_polkit_agent_error", "eip_no_tun_kext_error", diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 5357bed5..fe7b566a 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -31,6 +31,7 @@ from twisted.python import log import zope.interface import zope.proxy +from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister @@ -589,6 +590,47 @@ class EIP(object): self._signaler.signal( self._signaler.eip_get_gateways_list, gateways) + def get_gateway_country_code(self, domain): + """ + Signal the country code for the currently used gateway for the given + provider. + + :param domain: the domain to get country code. + :type domain: str + + Signals: + eip_get_gateway_country_code -> str + eip_no_gateway + """ + leap_settings = LeapSettings() + + eip_config = eipconfig.EIPConfig() + provider_config = ProviderConfig.get_provider_config(domain) + + api_version = provider_config.get_api_version() + eip_config.set_api_version(api_version) + eip_config.load(eipconfig.get_eipconfig_path(domain)) + + gateway_selector = eipconfig.VPNGatewaySelector(eip_config) + gateway_conf = leap_settings.get_selected_gateway(domain) + + if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: + gateways = gateway_selector.get_gateways() + else: + gateways = [gateway_conf] + + if not gateways: + self._signaler.signal(self._signaler.eip_no_gateway) + return + + # this only works for selecting the first gateway, as we're + # currently doing. + ccodes = gateway_selector.get_gateways_country_code() + gateway_ccode = ccodes[gateways[0]] + + self._signaler.signal(self._signaler.eip_get_gateway_country_code, + gateway_ccode) + def _can_start(self, domain): """ Returns True if it has everything that is needed to run EIP, diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index 4794d988..3bc7a513 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -256,6 +256,19 @@ class LeapBackend(Backend): """ self._eip.get_gateways_list(domain) + def eip_get_gateway_country_code(self, domain): + """ + Signal a list of gateways for the given provider. + + :param domain: the domain to get the gateways. + :type domain: str + + Signals: + eip_get_gateways_list -> str + eip_no_gateway + """ + self._eip.get_gateway_country_code(domain) + def eip_get_initialized_providers(self, domains): """ Signal a list of the given domains and if they are initialized or not. diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py index 47df0911..7912fc20 100644 --- a/src/leap/bitmask/backend/leapsignaler.py +++ b/src/leap/bitmask/backend/leapsignaler.py @@ -37,10 +37,12 @@ class LeapSignaler(SignalerQt): eip_disconnected = QtCore.Signal(object) eip_dns_error = QtCore.Signal() eip_dns_ok = QtCore.Signal() + eip_get_gateway_country_code = QtCore.Signal(object) eip_get_gateways_list = QtCore.Signal(object) eip_get_gateways_list_error = QtCore.Signal() eip_get_initialized_providers = QtCore.Signal(object) eip_network_unreachable = QtCore.Signal() + eip_no_gateway = QtCore.Signal() eip_no_pkexec_error = QtCore.Signal() eip_no_polkit_agent_error = QtCore.Signal() eip_no_tun_kext_error = QtCore.Signal() diff --git a/src/leap/bitmask/config/flags.py b/src/leap/bitmask/config/flags.py index 2f3fdde4..6b70659d 100644 --- a/src/leap/bitmask/config/flags.py +++ b/src/leap/bitmask/config/flags.py @@ -55,5 +55,3 @@ OPENVPN_VERBOSITY = 1 # Skip the checks in the wizard, use for testing purposes only! SKIP_WIZARD_CHECKS = False - -CURRENT_VPN_COUNTRY = None diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 01966d82..df9f3741 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -589,16 +589,23 @@ class EIPStatusWidget(QtGui.QWidget): self._systray.setIcon(QtGui.QIcon(selected_pixmap_tray)) self._eip_status_menu.setTitle(tray_message) - def set_provider(self, provider): + def set_provider(self, provider, country_code): + """ + Set the provider used right now, name and flag (if available). + + :param provider: the provider in use. + :type provider: str + :param country_code: the country code of the gateway in use. + :type country_code: str + """ self._provider = provider self.ui.lblEIPMessage.setText( self.tr("Routing traffic through: {0}").format( provider)) - ccode = flags.CURRENT_VPN_COUNTRY - if ccode is not None: - self.set_country_code(ccode) + if country_code is not None: + self.set_country_code(country_code) def set_country_code(self, code): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a77f0215..5549c9cb 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -412,6 +412,9 @@ class MainWindow(QtGui.QMainWindow): sig.eip_dns_error.connect(self._eip_dns_error) + sig.eip_get_gateway_country_code.connect(self._set_eip_provider) + sig.eip_no_gateway.connect(self._set_eip_provider) + # ================================================================== # Soledad signals @@ -1481,15 +1484,28 @@ class MainWindow(QtGui.QMainWindow): signal that currently is beeing processed under status_panel. After the refactor to EIPConductor this should not be necessary. """ - domain = self._login_widget.get_selected_provider() + self._already_started_eip = True - self._eip_status.set_provider(domain) + domain = self._login_widget.get_selected_provider() self._settings.set_defaultprovider(domain) - self._already_started_eip = True + + self._backend.eip_get_gateway_country_code(domain=domain) # check for connectivity self._backend.eip_check_dns(domain=domain) + @QtCore.Slot() + def _set_eip_provider(self, country_code=None): + """ + TRIGGERS: + Signaler.eip_get_gateway_country_code + Signaler.eip_no_gateway + + Set the current provider and country code in the eip status widget. + """ + domain = self._login_widget.get_selected_provider() + self._eip_status.set_provider(domain, country_code) + @QtCore.Slot() def _eip_dns_error(self): """ diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py index 0731bee3..5e2a4743 100644 --- a/src/leap/bitmask/services/eip/vpnlauncher.py +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -136,12 +136,6 @@ class VPNLauncher(object): logger.error('No gateway was found!') raise VPNLauncherException('No gateway was found!') - # this only works for selecting the first gateway, as we're - # currently doing. - ccodes = gateway_selector.get_gateways_country_code() - gateway_ccode = ccodes[gateways[0]] - flags.CURRENT_VPN_COUNTRY = gateway_ccode - logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) return gateways -- cgit v1.2.3 From 0cab909f9518273d95e371e5fb1061fb9b0a92fd Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 12:52:31 -0300 Subject: Send the flag module values to the processes. Add serialize/deserialize to dict helper. --- src/leap/bitmask/app.py | 8 +++++--- src/leap/bitmask/backend_app.py | 13 ++++++++++++- src/leap/bitmask/frontend_app.py | 7 ++++++- src/leap/bitmask/util/__init__.py | 25 +++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 43dabad3..d1a2a111 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -53,7 +53,7 @@ from leap.bitmask.backend_app import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber -from leap.bitmask.util import leap_argparse +from leap.bitmask.util import leap_argparse, flags_to_dict from leap.bitmask.util.requirement_checker import check_requirements from leap.common.events import server as event_server @@ -178,11 +178,13 @@ def start_app(): generate_certificates() - app = lambda: run_frontend(options=options) + flags_dict = flags_to_dict() + + app = lambda: run_frontend(options, flags_dict) gui_process = multiprocessing.Process(target=app) gui_process.start() - backend = lambda: run_backend(bypass_checks=opts.danger) + backend = lambda: run_backend(opts.danger, flags_dict) backend_process = multiprocessing.Process(target=backend) backend_process.start() diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index bd3b8a1f..d4815d82 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -17,11 +17,22 @@ import signal from leap.bitmask.backend.leapbackend import LeapBackend +from leap.bitmask.util import dict_to_flags -def run_backend(bypass_checks=False): +def run_backend(bypass_checks, flags_dict): + """ + Run the backend for the application. + + :param bypass_checks: whether we should bypass the checks or not + :type bypass_checks: bool + :param flags_dict: a dict containing the flag values set on app start. + :type flags_dict: dict + """ # Ensure that the application quits using CTRL-C signal.signal(signal.SIGINT, signal.SIG_DFL) + dict_to_flags(flags_dict) + backend = LeapBackend(bypass_checks=bypass_checks) backend.run() diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 60f20e3c..1fe4cd0a 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -23,6 +23,7 @@ from PySide import QtCore, QtGui from leap.bitmask.config import flags from leap.bitmask.gui import locale_rc # noqa - silence pylint from leap.bitmask.gui.mainwindow import MainWindow +from leap.bitmask.util import dict_to_flags import logging logger = logging.getLogger(__name__) @@ -39,13 +40,17 @@ def sigint_handler(*args, **kwargs): mainwindow.quit() -def run_frontend(options): +def run_frontend(options, flags_dict): """ Run the GUI for the application. :param options: a dict of options parsed from the command line. :type options: dict + :param flags_dict: a dict containing the flag values set on app start. + :type flags_dict: dict """ + dict_to_flags(flags_dict) + start_hidden = options["start_hidden"] # We force the style if on KDE so that it doesn't load all the kde diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py index 25b86874..caa94ec7 100644 --- a/src/leap/bitmask/util/__init__.py +++ b/src/leap/bitmask/util/__init__.py @@ -129,3 +129,28 @@ def force_eval(items): return map(do_eval, items) else: return do_eval(items) + + +def dict_to_flags(values): + """ + Set the flags values given in the values dict. + If a value isn't provided then use the already existing one. + + :param values: the values to set. + :type values: dict. + """ + for k, v in values.items(): + setattr(flags, k, v) + + +def flags_to_dict(): + """ + Get the flags values in a dict. + + :return: the values of flags into a dict. + :rtype: dict. + """ + items = [i for i in dir(flags) if i[0] != '_'] + values = {i: getattr(flags, i) for i in items} + + return values -- cgit v1.2.3 From eab69607ba4a65acf5c7745134d74917c76c6bf8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 16:43:07 -0300 Subject: Remove twisted stopper from the GUI. --- src/leap/bitmask/gui/mainwindow.py | 3 --- src/leap/bitmask/gui/twisted_main.py | 43 ------------------------------------ 2 files changed, 46 deletions(-) delete mode 100644 src/leap/bitmask/gui/twisted_main.py (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 5549c9cb..9be6f15c 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -43,7 +43,6 @@ from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard -from leap.bitmask.gui import twisted_main from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform @@ -1837,5 +1836,3 @@ class MainWindow(QtGui.QMainWindow): WindowsLock.release_all_locks() self.close() - - QtDelayedCall(100, twisted_main.quit) diff --git a/src/leap/bitmask/gui/twisted_main.py b/src/leap/bitmask/gui/twisted_main.py deleted file mode 100644 index b1ce0ead..00000000 --- a/src/leap/bitmask/gui/twisted_main.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -# twisted_main.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 . -""" -Main functions for integration of twisted reactor -""" -import logging - -from twisted.internet import error, reactor -from PySide import QtCore - -logger = logging.getLogger(__name__) - - -def stop(): - QtCore.QCoreApplication.sendPostedEvents() - QtCore.QCoreApplication.flush() - try: - reactor.stop() - logger.debug('Twisted reactor stopped') - except error.ReactorNotRunning: - logger.debug('Twisted reactor not running') - logger.debug("Done stopping all the things.") - - -def quit(): - """ - Stop the mainloop. - """ - reactor.callLater(0, stop) -- cgit v1.2.3 From c3f485e194eb32939755178b11d472e1e69a94ad Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 16:43:58 -0300 Subject: Handle SIGINT/SIGTERM in processes. --- src/leap/bitmask/app.py | 36 +++++++++++++++++++++++++++++---- src/leap/bitmask/backend_app.py | 26 ++++++++++++++++++++++-- src/leap/bitmask/frontend_app.py | 43 ++++++++++++++++++++++++++++------------ 3 files changed, 86 insertions(+), 19 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index d1a2a111..fa244470 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -44,6 +44,8 @@ import os import signal import sys +from functools import partial + from leap.bitmask.backend.utils import generate_certificates from leap.bitmask import __version__ as VERSION @@ -109,12 +111,33 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct +def sigterm_handler(logger, gui_process, backend_process, signum, frame): + """ + Signal handler that quits the running app cleanly. + + :param logger: the configured logger object. + :type logger: logging.Logger + :param gui_process: the GUI process + :type gui_process: multiprocessing.Process + :param backend_process: the backend process + :type backend_process: multiprocessing.Process + :param signum: number of the signal received (e.g. SIGINT -> 2) + :type signum: int + :param frame: current stack frame + :type frame: frame or None + """ + logger.debug("SIGTERM catched, terminating processes.") + gui_process.terminate() + # Don't terminate the backend, the frontend takes care of that. + # backend_process.terminate() + + def start_app(): """ Starts the main event loop and launches the main window. """ - # Ensure that the application quits using CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) + # Ignore the signals since we handle them in the subprocesses + # signal.signal(signal.SIGINT, signal.SIG_IGN) # Parse arguments and store them opts = leap_argparse.get_options() @@ -181,13 +204,18 @@ def start_app(): flags_dict = flags_to_dict() app = lambda: run_frontend(options, flags_dict) - gui_process = multiprocessing.Process(target=app) + gui_process = multiprocessing.Process(target=app, name='Frontend') gui_process.start() backend = lambda: run_backend(opts.danger, flags_dict) - backend_process = multiprocessing.Process(target=backend) + backend_process = multiprocessing.Process(target=backend, name='Backend') backend_process.start() + handle_sigterm = partial(sigterm_handler, logger, + gui_process, backend_process) + signal.signal(signal.SIGTERM, handle_sigterm) + signal.signal(signal.SIGINT, handle_sigterm) + if __name__ == "__main__": start_app() diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index d4815d82..b6d00f2d 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -14,11 +14,32 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import logging +import multiprocessing import signal from leap.bitmask.backend.leapbackend import LeapBackend from leap.bitmask.util import dict_to_flags +logger = logging.getLogger(__name__) + + +def signal_handler(signum, frame): + """ + Signal handler that quits the running app cleanly. + + :param signum: number of the signal received (e.g. SIGINT -> 2) + :type signum: int + :param frame: current stack frame + :type frame: frame or None + """ + # Note: we don't stop the backend in here since the frontend signal handler + # will take care of that. + # In the future we may need to do the stop in here when the frontend and + # the backend are run separately (without multiprocessing) + pname = multiprocessing.current_process().name + logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) + def run_backend(bypass_checks, flags_dict): """ @@ -29,8 +50,9 @@ def run_backend(bypass_checks, flags_dict): :param flags_dict: a dict containing the flag values set on app start. :type flags_dict: dict """ - # Ensure that the application quits using CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) + # ignore SIGINT since app.py takes care of signaling SIGTERM to us. + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal_handler) dict_to_flags(flags_dict) diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 1fe4cd0a..5dc42287 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -14,10 +14,13 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import multiprocessing import signal import sys import os +from functools import partial + from PySide import QtCore, QtGui from leap.bitmask.config import flags @@ -29,15 +32,20 @@ import logging logger = logging.getLogger(__name__) -def sigint_handler(*args, **kwargs): +def signal_handler(window, signum, frame): """ - Signal handler for SIGINT + Signal handler that quits the running app cleanly. + + :param window: a window with a `quit` callable + :type window: MainWindow + :param signum: number of the signal received (e.g. SIGINT -> 2) + :type signum: int + :param frame: current stack frame + :type frame: frame or None """ - logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGINT catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() + pname = multiprocessing.current_process().name + logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) + window.quit() def run_frontend(options, flags_dict): @@ -79,12 +87,21 @@ def run_frontend(options, flags_dict): qApp.setApplicationName("leap") qApp.setOrganizationDomain("leap.se") - MainWindow(start_hidden=start_hidden) - - # sigint_window = partial(sigint_handler, window, logger=logger) - # signal.signal(signal.SIGINT, sigint_window) - # Ensure that the application quits using CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) + # HACK: + # We need to do some 'python work' once in a while, otherwise, no python + # code will be called and the Qt event loop will prevent the signal + # handlers for SIGINT/SIGTERM to be called. + # see: http://stackoverflow.com/a/4939113/687989 + timer = QtCore.QTimer() + timer.start(500) # You may change this if you wish. + timer.timeout.connect(lambda: None) # Let the interpreter run each 500 ms. + + window = MainWindow(start_hidden=start_hidden) + + sigterm_handler = partial(signal_handler, window) + # ignore SIGINT since app.py takes care of signaling SIGTERM to us. + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, sigterm_handler) sys.exit(qApp.exec_()) -- cgit v1.2.3 From d33e9a2bc07ccd983a1321b254cc27ca6be989a3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 8 Jul 2014 17:01:18 -0300 Subject: Add file docstrings. --- src/leap/bitmask/backend/backend_proxy.py | 4 ++++ src/leap/bitmask/backend/leapsignaler.py | 5 ++++- src/leap/bitmask/backend/signaler.py | 4 ++++ src/leap/bitmask/backend/signaler_qt.py | 4 ++++ src/leap/bitmask/backend/utils.py | 3 +++ src/leap/bitmask/backend_app.py | 3 +++ src/leap/bitmask/frontend_app.py | 3 +++ 7 files changed, 25 insertions(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index 3c8e5d0f..39ed322e 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -14,6 +14,10 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +The BackendProxy handles calls from the GUI and forwards (through ZMQ) +to the backend. +""" import functools import Queue import threading diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py index 7912fc20..a36e6fdc 100644 --- a/src/leap/bitmask/backend/leapsignaler.py +++ b/src/leap/bitmask/backend/leapsignaler.py @@ -14,6 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Signaling server, used to define the API signals. +""" from PySide import QtCore from leap.bitmask.backend.signaler_qt import SignalerQt @@ -21,7 +24,7 @@ from leap.bitmask.backend.signaler_qt import SignalerQt class LeapSignaler(SignalerQt): """ - Signaling server subclass, used to defines the API signals. + Signaling server subclass, used to define the API signals. """ backend_bad_call = QtCore.Signal(object) diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index f8753771..6a0ec88a 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -14,6 +14,10 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Signaler client. +Receives signals from the backend and sends to the signaling server. +""" import Queue import threading import time diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py index dabd6662..ce9c24f5 100644 --- a/src/leap/bitmask/backend/signaler_qt.py +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -14,6 +14,10 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Signaling server. +Receives signals from the signaling client and emit Qt signals for the GUI. +""" import threading import time diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py index 5d600689..b71fab9e 100644 --- a/src/leap/bitmask/backend/utils.py +++ b/src/leap/bitmask/backend/utils.py @@ -14,6 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Backend utilities to handle ZMQ certificates. +""" import os import shutil diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index b6d00f2d..5c0e4803 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -14,6 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Start point for the Backend. +""" import logging import multiprocessing import signal diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 5dc42287..95d36538 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -14,6 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +Start point for the Frontend. +""" import multiprocessing import signal import sys -- cgit v1.2.3 From d8152277022eedf5a88c84cc5f099b2fc9ad6e46 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 9 Jul 2014 16:14:58 -0300 Subject: Comment out overly verbose logs for communication. --- src/leap/bitmask/backend/backend.py | 6 +++--- src/leap/bitmask/backend/backend_proxy.py | 10 ++++++---- src/leap/bitmask/backend/signaler.py | 10 ++++++---- src/leap/bitmask/backend/signaler_qt.py | 4 ++-- 4 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 5f696f75..833f4368 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -86,7 +86,7 @@ class Backend(object): try: request = self._zmq_socket.recv(zmq.NOBLOCK) self._zmq_socket.send("OK") - logger.debug("Received request: '{0}'".format(request)) + # logger.debug("Received request: '{0}'".format(request)) self._process_request(request) except zmq.ZMQError as e: if e.errno != zmq.EAGAIN: @@ -180,8 +180,8 @@ class Backend(object): if kwargs is not None: method = lambda: func(**kwargs) - logger.debug("Running method: '{0}' " - "with args: '{1}' in a thread".format(api_method, kwargs)) + # logger.debug("Running method: '{0}' " + # "with args: '{1}' in a thread".format(api_method, kwargs)) # run the action in a thread and keep track of it d = threads.deferToThread(method) diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index 39ed322e..f683e465 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -131,14 +131,16 @@ class BackendProxy(object): :param request: the request to send. :type request: str """ - logger.debug("Sending request to backend: {0}".format(request)) + # logger.debug("Sending request to backend: {0}".format(request)) self._socket.send(request) try: # Get the reply. - response = self._socket.recv() - msg = "Received reply for '{0}' -> '{1}'".format(request, response) - logger.debug(msg) + self._socket.recv() + # response = self._socket.recv() + # msg = "Received reply for '{0}' -> '{1}'" + # msg = msg.format(request, response) + # logger.debug(msg) except zmq.error.Again as e: msg = "Timeout error contacting backend. {0!r}".format(e) logger.critical(msg) diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index 6a0ec88a..f21f0998 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -145,14 +145,16 @@ class Signaler(object): :param request: the request to send. :type request: str """ - logger.debug("Signaling '{0}'".format(request)) + # logger.debug("Signaling '{0}'".format(request)) self._socket.send(request) # Get the reply. try: - response = self._socket.recv() - msg = "Received reply for '{0}' -> '{1}'".format(request, response) - logger.debug(msg) + self._socket.recv() + # response = self._socket.recv() + # msg = "Received reply for '{0}' -> '{1}'" + # msg = msg.format(request, response) + # logger.debug(msg) except zmq.error.Again as e: msg = "Timeout error contacting signaler. {0!r}".format(e) logger.critical(msg) diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py index ce9c24f5..4ec27a1e 100644 --- a/src/leap/bitmask/backend/signaler_qt.py +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -72,7 +72,7 @@ class SignalerQt(QtCore.QThread): # Wait for next request from client try: request = socket.recv(zmq.NOBLOCK) - logger.debug("Received request: '{0}'".format(request)) + # logger.debug("Received request: '{0}'".format(request)) socket.send("OK") self._process_request(request) except zmq.ZMQError as e: @@ -116,7 +116,7 @@ class SignalerQt(QtCore.QThread): logger.warning("Signal not implemented, '{0}'".format(signal)) return - logger.debug("Emitting '{0}'".format(signal)) + # logger.debug("Emitting '{0}'".format(signal)) if data is None: qt_signal.emit() else: -- cgit v1.2.3 From 525433088d6fbe3392af90942272dfd5dd2511d6 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 11 Jul 2014 12:28:20 -0300 Subject: Use main process to run frontend. Running the GUI in a child process gives problems on OSX. Also, change signal handling since we have less processes. --- src/leap/bitmask/app.py | 34 +++------------------------------- src/leap/bitmask/frontend_app.py | 7 +++---- 2 files changed, 6 insertions(+), 35 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index fa244470..e80b9dd1 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -41,10 +41,8 @@ # (thanks to: http://www.glassgiant.com/ascii/) import multiprocessing import os -import signal import sys -from functools import partial from leap.bitmask.backend.utils import generate_certificates @@ -111,27 +109,6 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct -def sigterm_handler(logger, gui_process, backend_process, signum, frame): - """ - Signal handler that quits the running app cleanly. - - :param logger: the configured logger object. - :type logger: logging.Logger - :param gui_process: the GUI process - :type gui_process: multiprocessing.Process - :param backend_process: the backend process - :type backend_process: multiprocessing.Process - :param signum: number of the signal received (e.g. SIGINT -> 2) - :type signum: int - :param frame: current stack frame - :type frame: frame or None - """ - logger.debug("SIGTERM catched, terminating processes.") - gui_process.terminate() - # Don't terminate the backend, the frontend takes care of that. - # backend_process.terminate() - - def start_app(): """ Starts the main event loop and launches the main window. @@ -203,18 +180,13 @@ def start_app(): flags_dict = flags_to_dict() - app = lambda: run_frontend(options, flags_dict) - gui_process = multiprocessing.Process(target=app, name='Frontend') - gui_process.start() - backend = lambda: run_backend(opts.danger, flags_dict) backend_process = multiprocessing.Process(target=backend, name='Backend') + backend_process.daemon = True backend_process.start() - handle_sigterm = partial(sigterm_handler, logger, - gui_process, backend_process) - signal.signal(signal.SIGTERM, handle_sigterm) - signal.signal(signal.SIGINT, handle_sigterm) + run_frontend(options, flags_dict) + if __name__ == "__main__": diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 95d36538..ffcb61ad 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -101,10 +101,9 @@ def run_frontend(options, flags_dict): window = MainWindow(start_hidden=start_hidden) - sigterm_handler = partial(signal_handler, window) - # ignore SIGINT since app.py takes care of signaling SIGTERM to us. - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTERM, sigterm_handler) + sig_handler = partial(signal_handler, window) + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) sys.exit(qApp.exec_()) -- cgit v1.2.3 From 0aee7d6cbc3f2c0b764056966eeddc4057eafd08 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 11 Jul 2014 17:24:20 -0300 Subject: Use specific settings for backend. This way we get rid of Qt on the backend side. The use of QSettings in the backend was breaking the app on OSX. --- src/leap/bitmask/backend/api.py | 1 + src/leap/bitmask/backend/components.py | 8 +- src/leap/bitmask/backend/leapbackend.py | 14 +++ src/leap/bitmask/backend/settings.py | 158 ++++++++++++++++++++++++++ src/leap/bitmask/crypto/srpauth.py | 4 +- src/leap/bitmask/gui/eip_preferenceswindow.py | 2 + src/leap/bitmask/gui/mainwindow.py | 2 + src/leap/bitmask/services/eip/vpnlauncher.py | 8 +- src/leap/bitmask/services/mail/plumber.py | 4 +- 9 files changed, 189 insertions(+), 12 deletions(-) create mode 100644 src/leap/bitmask/backend/settings.py (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index f8b8c699..b8533f36 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -45,6 +45,7 @@ API = ( "provider_get_pinned_providers", "provider_get_supported_services", "provider_setup", + "settings_set_selected_gateway", "smtp_start_service", "smtp_stop_service", "soledad_bootstrap", diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index fe7b566a..8b471b14 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -31,7 +31,7 @@ from twisted.python import log import zope.interface import zope.proxy -from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.backend.settings import Settings, GATEWAY_AUTOMATIC from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister @@ -602,7 +602,7 @@ class EIP(object): eip_get_gateway_country_code -> str eip_no_gateway """ - leap_settings = LeapSettings() + settings = Settings() eip_config = eipconfig.EIPConfig() provider_config = ProviderConfig.get_provider_config(domain) @@ -612,9 +612,9 @@ class EIP(object): eip_config.load(eipconfig.get_eipconfig_path(domain)) gateway_selector = eipconfig.VPNGatewaySelector(eip_config) - gateway_conf = leap_settings.get_selected_gateway(domain) + gateway_conf = settings.get_selected_gateway(domain) - if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: + if gateway_conf == GATEWAY_AUTOMATIC: gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index 3bc7a513..d3c4fcda 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -24,6 +24,7 @@ import zope.proxy from leap.bitmask.backend import components from leap.bitmask.backend.backend import Backend +from leap.bitmask.backend.settings import Settings logger = logging.getLogger(__name__) @@ -41,6 +42,8 @@ class LeapBackend(Backend): """ Backend.__init__(self) + self._settings = Settings() + # Objects needed by several components, so we make a proxy and pass # them around self._soledad_proxy = zope.proxy.ProxyBase(None) @@ -515,3 +518,14 @@ class LeapBackend(Backend): imap_stopped """ self._mail.stop_imap_service() + + def settings_set_selected_gateway(self, provider, gateway): + """ + Set the selected gateway for a given provider. + + :param provider: provider domain + :type provider: str + :param gateway: gateway to use as default + :type gateway: str + """ + self._settings.set_selected_gateway(provider, gateway) diff --git a/src/leap/bitmask/backend/settings.py b/src/leap/bitmask/backend/settings.py new file mode 100644 index 00000000..5cb4c616 --- /dev/null +++ b/src/leap/bitmask/backend/settings.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# settings.py +# Copyright (C) 2013, 2014 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 . +""" +Backend settings +""" +import ConfigParser +import logging +import os + +from leap.bitmask.util import get_path_prefix +from leap.common.check import leap_assert, leap_assert_type + +logger = logging.getLogger(__name__) + +# We need this one available for the default decorator +GATEWAY_AUTOMATIC = "Automatic" +GENERAL_SECTION = "General" + + +class Settings(object): + """ + Leap backend settings hanler. + """ + CONFIG_NAME = "leap-backend.conf" + + # keys + GATEWAY_KEY = "Gateway" + + def __init__(self): + """ + Create the ConfigParser object and read it. + """ + self._settings_path = os.path.join(get_path_prefix(), + "leap", self.CONFIG_NAME) + + self._settings = ConfigParser.ConfigParser() + self._settings.read(self._settings_path) + + self._add_section(GENERAL_SECTION) + + def _add_section(self, section): + """ + Add `section` to the config file and don't fail if already exists. + + :param section: the section to add. + :type section: str + """ + self._settings.read(self._settings_path) + try: + self._settings.add_section(section) + except ConfigParser.DuplicateSectionError: + pass + + def _save(self): + """ + Save the current state to the config file. + """ + with open(self._settings_path, 'wb') as f: + self._settings.write(f) + + def _get_value(self, section, key, default): + """ + Return the value for the fiven `key` in `section`. + If there's no such section/key, `default` is returned. + + :param section: the section to get the value from. + :type section: str + :param key: the key which value we want to get. + :type key: str + :param default: the value to return if there is no section/key. + :type default: object + + :rtype: object + """ + try: + return self._settings.get(section, key) + except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): + return default + + def get_selected_gateway(self, provider): + """ + Return the configured gateway for the given `provider`. + + :param provider: provider domain + :type provider: str + + :rtype: str + """ + leap_assert(len(provider) > 0, "We need a nonempty provider") + return self._get_value(provider, self.GATEWAY_KEY, GATEWAY_AUTOMATIC) + + def set_selected_gateway(self, provider, gateway): + """ + Saves the configured gateway for the given provider + + :param provider: provider domain + :type provider: str + + :param gateway: gateway to use as default + :type gateway: str + """ + + leap_assert(len(provider) > 0, "We need a nonempty provider") + leap_assert_type(gateway, (str, unicode)) + + self._add_section(provider) + + self._settings.set(provider, self.GATEWAY_KEY, gateway) + self._save() + + def get_uuid(self, username): + """ + Gets the uuid for a given username. + + :param username: the full user identifier in the form user@provider + :type username: basestring + """ + leap_assert("@" in username, + "Expected username in the form user@provider") + user, provider = username.split('@') + + return self._get_value(provider, username, "") + + def set_uuid(self, username, value): + """ + Sets the uuid for a given username. + + :param username: the full user identifier in the form user@provider + :type username: str or unicode + :param value: the uuid to save or None to remove it + :type value: str or unicode or None + """ + leap_assert("@" in username, + "Expected username in the form user@provider") + user, provider = username.split('@') + + if value is None: + self._settings.remove_option(provider, username) + else: + leap_assert(len(value) > 0, "We cannot save an empty uuid") + self._add_section(provider) + self._settings.set(provider, username, value) + + self._save() diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index 856d2c81..67c686b0 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -32,7 +32,7 @@ from requests.adapters import HTTPAdapter from twisted.internet import threads from twisted.internet.defer import CancelledError -from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.backend.settings import Settings from leap.bitmask.util import request_helpers as reqhelper from leap.bitmask.util.compat import requests_has_max_retries from leap.bitmask.util.constants import REQUEST_TIMEOUT @@ -151,7 +151,7 @@ class SRPAuth(object): self._provider_config = provider_config self._signaler = signaler - self._settings = LeapSettings() + self._settings = Settings() # **************************************************** # # Dependency injection helpers, override this for more diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py index 306fdb8c..0f63972f 100644 --- a/src/leap/bitmask/gui/eip_preferenceswindow.py +++ b/src/leap/bitmask/gui/eip_preferenceswindow.py @@ -149,6 +149,8 @@ class EIPPreferencesWindow(QtGui.QDialog): gateway = self.ui.cbGateways.itemData(idx) self._settings.set_selected_gateway(provider, gateway) + self._backend.settings_set_selected_gateway(provider=provider, + gateway=gateway) msg = self.tr( "Gateway settings for provider '{0}' saved.").format(provider) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 9be6f15c..27c7f717 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -129,6 +129,8 @@ class MainWindow(QtGui.QMainWindow): self._leap_signaler.start() self._settings = LeapSettings() + # gateway = self._settings.get_selected_gateway(provider) + # self._backend.settings_set_selected_gateway(provider, gateway) # Login Widget self._login_widget = LoginWidget(self._settings, self) diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py index 5e2a4743..e36fd76b 100644 --- a/src/leap/bitmask/services/eip/vpnlauncher.py +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -27,7 +27,7 @@ from abc import ABCMeta, abstractmethod from functools import partial from leap.bitmask.config import flags -from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.backend.settings import Settings, GATEWAY_AUTOMATIC from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector @@ -122,12 +122,12 @@ class VPNLauncher(object): :rtype: list """ gateways = [] - leap_settings = LeapSettings() + settings = Settings() domain = providerconfig.get_domain() - gateway_conf = leap_settings.get_selected_gateway(domain) + gateway_conf = settings.get_selected_gateway(domain) gateway_selector = VPNGatewaySelector(eipconfig) - if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: + if gateway_conf == GATEWAY_AUTOMATIC: gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py index 1ef0543e..fa33afcd 100644 --- a/src/leap/bitmask/services/mail/plumber.py +++ b/src/leap/bitmask/services/mail/plumber.py @@ -26,7 +26,7 @@ from functools import partial from twisted.internet import defer -from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.backend.settings import Settings from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.provider import get_provider_path from leap.bitmask.services.soledad.soledadbootstrapper import get_db_paths @@ -114,7 +114,7 @@ class MBOXPlumber(object): self.user = user self.mdir = mdir self.sol = None - self._settings = LeapSettings() + self._settings = Settings() provider_config_path = os.path.join(get_path_prefix(), get_provider_path(provider)) -- cgit v1.2.3 From cd8f6757b51a8eedc3e29c22656ade1ae22110fe Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 12:08:37 -0300 Subject: Apply changes removed rebasing pullreq #679. https://github.com/leapcode/bitmask_client/pull/679/files --- src/leap/bitmask/frontend_app.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index ffcb61ad..51607d0b 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -27,7 +27,6 @@ from functools import partial from PySide import QtCore, QtGui from leap.bitmask.config import flags -from leap.bitmask.gui import locale_rc # noqa - silence pylint from leap.bitmask.gui.mainwindow import MainWindow from leap.bitmask.util import dict_to_flags @@ -35,20 +34,24 @@ import logging logger = logging.getLogger(__name__) -def signal_handler(window, signum, frame): +def signal_handler(window, pid, signum, frame): """ Signal handler that quits the running app cleanly. :param window: a window with a `quit` callable :type window: MainWindow + :param pid: process id of the main process. + :type pid: int :param signum: number of the signal received (e.g. SIGINT -> 2) :type signum: int :param frame: current stack frame :type frame: frame or None """ - pname = multiprocessing.current_process().name - logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) - window.quit() + my_pid = os.getpid() + if pid == my_pid: + pname = multiprocessing.current_process().name + logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) + window.quit() def run_frontend(options, flags_dict): @@ -101,7 +104,8 @@ def run_frontend(options, flags_dict): window = MainWindow(start_hidden=start_hidden) - sig_handler = partial(signal_handler, window) + my_pid = os.getpid() + sig_handler = partial(signal_handler, window, my_pid) signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGTERM, sig_handler) -- cgit v1.2.3 From d6cee5b46587367b558863292f71f5baafadc762 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 12:23:13 -0300 Subject: pep8 fixes --- src/leap/bitmask/app.py | 1 - src/leap/bitmask/gui/mainwindow.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index e80b9dd1..88f6bc15 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -188,6 +188,5 @@ def start_app(): run_frontend(options, flags_dict) - if __name__ == "__main__": start_app() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 27c7f717..3d489bd8 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -256,7 +256,7 @@ class MainWindow(QtGui.QMainWindow): # XXX should connect to mail_conductor.start_mail_service instead self.soledad_ready.connect(self._start_smtp_bootstrapping) self.soledad_ready.connect(self._start_imap_service) - ################################# end Qt Signals connection ######## + # ################################ end Qt Signals connection ######## init_platform() @@ -1295,7 +1295,7 @@ class MainWindow(QtGui.QMainWindow): sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True)) sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True)) - if not MX_SERVICE in self._provider_details['services']: + if MX_SERVICE not in self._provider_details['services']: self._set_mx_visible(False) def _start_eip_bootstrap(self): -- cgit v1.2.3 From fad58792a499f5b3e7ef28c68d0bae7f055c603d Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 14:32:28 -0300 Subject: Use custom `mkdir` to create the tree if needed. --- src/leap/bitmask/backend/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py index b71fab9e..54a16fd7 100644 --- a/src/leap/bitmask/backend/utils.py +++ b/src/leap/bitmask/backend/utils.py @@ -23,6 +23,7 @@ import shutil import zmq.auth from leap.bitmask.util import get_path_prefix +from leap.common.files import mkdir_p KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates') @@ -34,7 +35,7 @@ def generate_certificates(): # Create directory for certificates, remove old content if necessary if os.path.exists(KEYS_DIR): shutil.rmtree(KEYS_DIR) - os.mkdir(KEYS_DIR) + mkdir_p(KEYS_DIR) # create new keys in certificates dir # public_file, secret_file = create_certificates(...) -- cgit v1.2.3 From 662ae7107bde734cda8d4bc08f5b647650139b61 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 15:20:05 -0300 Subject: Prevent quit() being called more than once. --- src/leap/bitmask/gui/mainwindow.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 3d489bd8..6959650b 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -187,6 +187,7 @@ class MainWindow(QtGui.QMainWindow): self._services_being_stopped = {} # used to know if we are in the final steps of quitting + self._quitting = False self._finally_quitting = False self._backend_connected_signals = [] @@ -1762,8 +1763,10 @@ class MainWindow(QtGui.QMainWindow): Start the quit sequence and wait for services to finish. Cleanup and close the main window before quitting. """ - # TODO separate the shutting down of services from the - # UI stuff. + if self._quitting: + return + + self._quitting = True # first thing to do quitting, hide the mainwindow and show tooltip. self.hide() -- cgit v1.2.3 From 57ac3750970777bb5b6e372e5eb00f3144098d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Mon, 14 Jul 2014 16:24:59 -0300 Subject: Support EIP in OSX --- src/leap/bitmask/backend/components.py | 3 ++- src/leap/bitmask/services/eip/darwinvpnlauncher.py | 4 +++- src/leap/bitmask/services/eip/vpnprocess.py | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 8b471b14..8fa8b285 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -649,7 +649,8 @@ class EIP(object): launcher = get_vpn_launcher() ovpn_path = force_eval(launcher.OPENVPN_BIN_PATH) if not os.path.isfile(ovpn_path): - logger.error("Cannot start OpenVPN, binary not found") + logger.error("Cannot start OpenVPN, binary not found: %s" % + (ovpn_path,)) return False # check for other problems diff --git a/src/leap/bitmask/services/eip/darwinvpnlauncher.py b/src/leap/bitmask/services/eip/darwinvpnlauncher.py index 41d75052..f83e0170 100644 --- a/src/leap/bitmask/services/eip/darwinvpnlauncher.py +++ b/src/leap/bitmask/services/eip/darwinvpnlauncher.py @@ -46,7 +46,9 @@ class DarwinVPNLauncher(VPNLauncher): INSTALL_MSG = ("\"Bitmask needs administrative privileges to install " "missing scripts and fix permissions.\"") - INSTALL_PATH = os.path.realpath(os.getcwd() + "/../../") + # Hardcode the installation path for OSX for security, openvpn is + # run as root + INSTALL_PATH = "/Applications/Bitmask.app/" INSTALL_PATH_ESCAPED = os.path.realpath(os.getcwd() + "/../../") OPENVPN_BIN = 'openvpn.leap' OPENVPN_PATH = "%s/Contents/Resources/openvpn" % (INSTALL_PATH,) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index 3bda3059..1c11a337 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -255,6 +255,9 @@ class VPN(object): """ Tear the firewall down using the privileged wrapper. """ + if IS_MAC: + # We don't support Mac so far + return True BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT) exitCode = subprocess.call(["pkexec", BM_ROOT, "firewall", "stop"]) -- cgit v1.2.3 From 7c7c2d49b172d08e106e297101142747eaf78944 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 16:23:20 -0300 Subject: Use polling to prevent communication issues. --- src/leap/bitmask/backend/signaler.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index f21f0998..7401f3a0 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -38,6 +38,8 @@ class Signaler(object): """ PORT = "5667" SERVER = "tcp://localhost:%s" % PORT + POLL_TIMEOUT = 1000 # ms + POLL_TRIES = 3 def __init__(self): """ @@ -148,13 +150,23 @@ class Signaler(object): # logger.debug("Signaling '{0}'".format(request)) self._socket.send(request) - # Get the reply. - try: - self._socket.recv() - # response = self._socket.recv() - # msg = "Received reply for '{0}' -> '{1}'" - # msg = msg.format(request, response) - # logger.debug(msg) - except zmq.error.Again as e: - msg = "Timeout error contacting signaler. {0!r}".format(e) + poll = zmq.Poller() + poll.register(self._socket, zmq.POLLIN) + + reply = None + tries = 0 + + while tries < self.POLL_TRIES: + socks = dict(poll.poll(self.POLL_TIMEOUT)) + if socks.get(self._socket) == zmq.POLLIN: + reply = self._socket.recv() + break + + tries += 1 + + if reply is None: + msg = "Timeout error contacting backend." logger.critical(msg) + # else: + # msg = "Received reply for '{0}' -> '{1}'".format(request, reply) + # logger.debug(msg) -- cgit v1.2.3 From 986ff80c16efea0e32ff78012b2fd3c95b83e179 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 15 Jul 2014 16:24:49 -0300 Subject: Replace QThread with threading.Thread. --- src/leap/bitmask/backend/signaler_qt.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py index 4ec27a1e..433f18ed 100644 --- a/src/leap/bitmask/backend/signaler_qt.py +++ b/src/leap/bitmask/backend/signaler_qt.py @@ -33,7 +33,7 @@ import logging logger = logging.getLogger(__name__) -class SignalerQt(QtCore.QThread): +class SignalerQt(QtCore.QObject): """ Signaling server. Receives signals from the signaling client and emit Qt signals for the GUI. @@ -42,11 +42,24 @@ class SignalerQt(QtCore.QThread): BIND_ADDR = "tcp://127.0.0.1:%s" % PORT def __init__(self): - QtCore.QThread.__init__(self) + QtCore.QObject.__init__(self) + + # Note: we use a plain thread instead of a QThread since works better. + # The signaler was not responding on OSX if the worker loop was run in + # a QThread. + # Possibly, ZMQ was not getting cycles to do work because Qt not + # receiving focus or something. + self._worker_thread = threading.Thread(target=self._run) self._do_work = threading.Event() + + def start(self): + """ + Start the worker thread for the signaler server. + """ self._do_work.set() + self._worker_thread.start() - def run(self): + def _run(self): """ Start a loop to process the ZMQ requests from the signaler client. """ -- cgit v1.2.3 From 432fcab9f838b0bfc81ed8d40d92b4b5d3854f24 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 16 Jul 2014 09:39:17 -0300 Subject: Code style fixes. --- src/leap/bitmask/__init__.py | 10 ++++----- src/leap/bitmask/backend/components.py | 6 ++--- src/leap/bitmask/config/provider_spec.py | 2 +- src/leap/bitmask/crypto/srpauth.py | 2 +- src/leap/bitmask/crypto/tests/fake_provider.py | 4 ++-- src/leap/bitmask/gui/eip_status.py | 11 +++++---- src/leap/bitmask/gui/statemachines.py | 11 +++++---- src/leap/bitmask/platform_init/initializers.py | 3 +-- src/leap/bitmask/provider/providerbootstrapper.py | 4 ++-- src/leap/bitmask/services/eip/conductor.py | 4 ++-- .../services/eip/tests/test_eipbootstrapper.py | 2 +- src/leap/bitmask/services/eip/vpnlauncher.py | 10 ++++----- src/leap/bitmask/services/eip/vpnprocess.py | 2 +- src/leap/bitmask/services/mail/plumber.py | 4 ++-- .../services/soledad/soledadbootstrapper.py | 2 +- .../services/tests/test_abstractbootstrapper.py | 2 +- src/leap/bitmask/util/leap_argparse.py | 26 +++++++++++----------- src/leap/bitmask/util/polkit_agent.py | 6 ++--- src/leap/bitmask/util/privilege_policies.py | 4 ++-- 19 files changed, 56 insertions(+), 59 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/__init__.py b/src/leap/bitmask/__init__.py index 03da1e2f..9ec5aae7 100644 --- a/src/leap/bitmask/__init__.py +++ b/src/leap/bitmask/__init__.py @@ -29,7 +29,7 @@ from leap.bitmask.util import first # place, it can't be technically imported, but that doesn't matter # because the import is never executed if False: - import _scrypt + import _scrypt # noqa - skip 'not used' warning def _is_release_version(version): @@ -66,16 +66,16 @@ try: IS_RELEASE_VERSION = _is_release_version(__version__) del get_versions except ImportError: - #running on a tree that has not run - #the setup.py setver + # running on a tree that has not run + # the setup.py setver pass __appname__ = "unknown" try: from leap.bitmask._appname import __appname__ except ImportError: - #running on a tree that has not run - #the setup.py setver + # running on a tree that has not run + # the setup.py setver pass __short_version__ = first(re.findall('\d+\.\d+\.\d+', __version__)) diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 8fa8b285..b372db89 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -486,9 +486,9 @@ class EIP(object): self._signaler.signal(self._signaler.eip_stopped) return else: - #msg = "Firewall is not down yet, waiting... {0} of {1}" - #msg = msg.format(retry, MAX_FW_WAIT_RETRIES) - #logger.debug(msg) + # msg = "Firewall is not down yet, waiting... {0} of {1}" + # msg = msg.format(retry, MAX_FW_WAIT_RETRIES) + # logger.debug(msg) time.sleep(FW_WAIT_STEP) retry += 1 logger.warning("After waiting, firewall is not down... " diff --git a/src/leap/bitmask/config/provider_spec.py b/src/leap/bitmask/config/provider_spec.py index cf942c7b..a1d91b90 100644 --- a/src/leap/bitmask/config/provider_spec.py +++ b/src/leap/bitmask/config/provider_spec.py @@ -37,7 +37,7 @@ leap_provider_spec = { 'default': {u'en': u'Test Provider'} }, 'description': { - #'type': LEAPTranslatable, + # 'type': LEAPTranslatable, 'type': dict, 'format': 'translatable', 'default': {u'en': u'Test provider'} diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index 67c686b0..d59b3c31 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -24,7 +24,7 @@ import requests import srp import json -#this error is raised from requests +# this error is raised from requests from simplejson.decoder import JSONDecodeError from functools import partial from requests.adapters import HTTPAdapter diff --git a/src/leap/bitmask/crypto/tests/fake_provider.py b/src/leap/bitmask/crypto/tests/fake_provider.py index b8cdbb12..60a3ef0a 100755 --- a/src/leap/bitmask/crypto/tests/fake_provider.py +++ b/src/leap/bitmask/crypto/tests/fake_provider.py @@ -156,7 +156,7 @@ def getSession(self, sessionInterface=None): put the right cookie name in place """ if not self.session: - #cookiename = b"_".join([b'TWISTED_SESSION'] + self.sitepath) + # cookiename = b"_".join([b'TWISTED_SESSION'] + self.sitepath) cookiename = b"_".join([b'_session_id'] + self.sitepath) sessionCookie = self.getCookie(cookiename) if sessionCookie: @@ -321,7 +321,7 @@ class OpenSSLServerContextFactory(object): Create an SSL context. """ ctx = SSL.Context(SSL.SSLv23_METHOD) - #ctx = SSL.Context(SSL.TLSv1_METHOD) + # ctx = SSL.Context(SSL.TLSv1_METHOD) ctx.use_certificate_file(where('leaptestscert.pem')) ctx.use_privatekey_file(where('leaptestskey.pem')) diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index df9f3741..a707050a 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -24,7 +24,6 @@ from functools import partial from PySide import QtCore, QtGui -from leap.bitmask.config import flags from leap.bitmask.services import get_service_display_name, EIP_SERVICE from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.util.averages import RateMovingAverage @@ -123,8 +122,8 @@ class EIPStatusWidget(QtGui.QWidget): # XXX we cannot connect this signal now because # it interferes with the proper notifications during restarts # without available network. - #signaler.eip_network_unreachable.connect( - #self._on_eip_network_unreachable) + # signaler.eip_network_unreachable.connect( + # self._on_eip_network_unreachable) def _make_status_clickable(self): """ @@ -326,7 +325,7 @@ class EIPStatusWidget(QtGui.QWidget): Triggered after a successful login. Enables the start button. """ - #logger.debug('Showing EIP start button') + # logger.debug('Showing EIP start button') self.eip_button.show() # Restore the eip action menu @@ -545,7 +544,7 @@ class EIPStatusWidget(QtGui.QWidget): elif vpn_state == "ALREADYRUNNING": # Put the following calls in Qt's event queue, otherwise # the UI won't update properly - #self.send_disconnect_signal() + # self.send_disconnect_signal() QtDelayedCall( 0, self.eipconnection.qtsigns.do_disconnect_signal.emit) msg = self.tr("Unable to start VPN, it's already running.") @@ -738,7 +737,7 @@ class EIPStatusWidget(QtGui.QWidget): self.set_eip_status_icon("error") def set_eipstatus_off(self, error=True): - # XXX this should be handled by the state machine. + # XXX this should be handled by the state machine. """ Sets eip status to off """ diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py index 00a1387e..91f1f605 100644 --- a/src/leap/bitmask/gui/statemachines.py +++ b/src/leap/bitmask/gui/statemachines.py @@ -240,9 +240,9 @@ class CompositeMachine(QStateMachine): c2.qtsigs.disconnected_signal.connect(self.off_ev2_slot) # XXX why is this getting deletec in c++? - #Traceback (most recent call last): - #self.postEvent(self.events.on_ev2) - #RuntimeError: Internal C++ object (ConnectedEvent2) already deleted. + # Traceback (most recent call last): + # self.postEvent(self.events.on_ev2) + # RuntimeError: Internal C++ object (ConnectedEvent2) already deleted. # XXX trying the following workaround, since # I cannot find why in the world this is getting deleted :( # XXX refactor! @@ -318,9 +318,8 @@ class ConnectionMachineBuilder(object): components = self._conn.components if components is None: - # simple case: connection definition inherits directly from - # the abstract connection. - + # simple case: connection definition inherits directly from + # the abstract connection. leap_assert_type(self._conn, connections.AbstractLEAPConnection) return self._make_simple_machine(self._conn, **kwargs) diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index 2d800703..e4d6f9b3 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -21,7 +21,6 @@ import logging import os import platform import stat -import sys import subprocess import tempfile @@ -103,7 +102,7 @@ def get_missing_helpers_dialog(): msg.setWindowTitle(msg.tr("Missing helper files")) msg.setText(msg.tr(WE_NEED_POWERS)) # but maybe the user really deserve to know more - #msg.setInformativeText(msg.tr(BECAUSE)) + # msg.setInformativeText(msg.tr(BECAUSE)) msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) msg.addButton("No, don't ask again", QtGui.QMessageBox.RejectRole) msg.setDefaultButton(QtGui.QMessageBox.Yes) diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py index 5064f6a4..71edbb87 100644 --- a/src/leap/bitmask/provider/providerbootstrapper.py +++ b/src/leap/bitmask/provider/providerbootstrapper.py @@ -194,8 +194,8 @@ class ProviderBootstrapper(AbstractBootstrapper): verify = self.verify if mtime: # the provider.json exists - # So, we're getting it from the api.* and checking against - # the provider ca. + # So, we're getting it from the api.* and checking against + # the provider ca. try: provider_config = ProviderConfig() provider_config.load(provider_json) diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index dfd27f3d..bb07809a 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -202,7 +202,7 @@ class EIPConductor(object): # we bypass the on_eip_disconnected here plug_restart_on_disconnected() self.qtsigs.disconnected_signal.emit() - #QtDelayedCall(0, self.qtsigs.disconnected_signal.emit) + # QtDelayedCall(0, self.qtsigs.disconnected_signal.emit) # ...and reconnect the original signal again, after having used the # diversion QtDelayedCall(500, reconnect_disconnected_signal) @@ -301,7 +301,7 @@ class EIPConductor(object): # XXX FIXME --- check exitcode is != 0 really. # bitmask-root is masking the exitcode, so we might need # to fix it on that side. - #if exitCode != 0 and not self.user_stopped_eip: + # if exitCode != 0 and not self.user_stopped_eip: if not self.user_stopped_eip: eip_status_label = self._eip_status.tr( "{0} finished in an unexpected manner!") diff --git a/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py b/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py index 6640a860..1888f2c9 100644 --- a/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py +++ b/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py @@ -30,7 +30,7 @@ import time try: import unittest2 as unittest except ImportError: - import unittest + import unittest # noqa - skip 'unused import' warning from nose.twistedtools import deferred, reactor from twisted.internet import threads diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py index e36fd76b..72e19413 100644 --- a/src/leap/bitmask/services/eip/vpnlauncher.py +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -169,11 +169,11 @@ class VPNLauncher(object): leap_assert_type(providerconfig, ProviderConfig) # XXX this still has to be changed on osx and windows accordingly - #kwargs = {} - #openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs) - #if not openvpn_possibilities: - #raise OpenVPNNotFoundException() - #openvpn = first(openvpn_possibilities) + # kwargs = {} + # openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs) + # if not openvpn_possibilities: + # raise OpenVPNNotFoundException() + # openvpn = first(openvpn_possibilities) # ----------------------------------------- openvpn_path = force_eval(kls.OPENVPN_BIN_PATH) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index 1c11a337..d1a3fdaa 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -817,7 +817,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): leap_assert_type(eipconfig, EIPConfig) leap_assert_type(providerconfig, ProviderConfig) - #leap_assert(not self.isRunning(), "Starting process more than once!") + # leap_assert(not self.isRunning(), "Starting process more than once!") self._eipconfig = eipconfig self._providerconfig = providerconfig diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py index fa33afcd..1af65c5d 100644 --- a/src/leap/bitmask/services/mail/plumber.py +++ b/src/leap/bitmask/services/mail/plumber.py @@ -232,8 +232,8 @@ class MBOXPlumber(object): with open(mail_filename) as f: mail_string = f.read() - #uid = self._mbox.getUIDNext() - #print "saving with UID: %s" % uid + # uid = self._mbox.getUIDNext() + # print "saving with UID: %s" % uid d = self._mbox.messages.add_msg( mail_string, notify_on_disk=True) return d diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index a5904dce..c4e43bfe 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -134,7 +134,7 @@ class SoledadBootstrapper(AbstractBootstrapper): MAX_INIT_RETRIES = 10 MAX_SYNC_RETRIES = 10 WAIT_MAX_SECONDS = 600 - #WAIT_STEP_SECONDS = 1 + # WAIT_STEP_SECONDS = 1 WAIT_STEP_SECONDS = 5 def __init__(self, signaler=None): diff --git a/src/leap/bitmask/services/tests/test_abstractbootstrapper.py b/src/leap/bitmask/services/tests/test_abstractbootstrapper.py index 3ac126ac..c3fda9e1 100644 --- a/src/leap/bitmask/services/tests/test_abstractbootstrapper.py +++ b/src/leap/bitmask/services/tests/test_abstractbootstrapper.py @@ -1,4 +1,4 @@ -## -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # test_abstrctbootstrapper.py # Copyright (C) 2013 LEAP # diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py index c7fed0a3..cbd6d8a5 100644 --- a/src/leap/bitmask/util/leap_argparse.py +++ b/src/leap/bitmask/util/leap_argparse.py @@ -107,19 +107,19 @@ def build_parser(): 'against domains.') # 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') + # 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 diff --git a/src/leap/bitmask/util/polkit_agent.py b/src/leap/bitmask/util/polkit_agent.py index 6fda2f88..7764f571 100644 --- a/src/leap/bitmask/util/polkit_agent.py +++ b/src/leap/bitmask/util/polkit_agent.py @@ -39,9 +39,9 @@ def _launch_agent(): logger.error('Exception while running polkit authentication agent ' '%s' % (exc,)) # XXX fix KDE launch. See: #3755 - #try: - #subprocess.call(KDE_PATH) - #except Exception as exc: + # try: + # subprocess.call(KDE_PATH) + # except Exception as exc: def launch(): diff --git a/src/leap/bitmask/util/privilege_policies.py b/src/leap/bitmask/util/privilege_policies.py index adc3503f..f894d73b 100644 --- a/src/leap/bitmask/util/privilege_policies.py +++ b/src/leap/bitmask/util/privilege_policies.py @@ -87,8 +87,8 @@ class LinuxPolicyChecker(PolicyChecker): else self.LINUX_POLKIT_FILE) def is_missing_policy_permissions(self): - # FIXME this name is quite confusing, it does not have anything to do with - # file permissions. + # FIXME this name is quite confusing, it does not have anything to do + # with file permissions. """ Returns True if we could not find the appropriate policykit file in place -- cgit v1.2.3 From 3d6629348aedf2a6863d242d96d64b3492e86f9a Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 16 Jul 2014 11:29:19 -0300 Subject: Increase timeout and retries. With this change we avoid the communication issues on OSX. --- src/leap/bitmask/backend/signaler.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py index 7401f3a0..574bfa71 100644 --- a/src/leap/bitmask/backend/signaler.py +++ b/src/leap/bitmask/backend/signaler.py @@ -38,8 +38,8 @@ class Signaler(object): """ PORT = "5667" SERVER = "tcp://localhost:%s" % PORT - POLL_TIMEOUT = 1000 # ms - POLL_TRIES = 3 + POLL_TIMEOUT = 2000 # ms + POLL_TRIES = 500 def __init__(self): """ @@ -156,13 +156,18 @@ class Signaler(object): reply = None tries = 0 - while tries < self.POLL_TRIES: + while True: socks = dict(poll.poll(self.POLL_TIMEOUT)) if socks.get(self._socket) == zmq.POLLIN: reply = self._socket.recv() break tries += 1 + if tries < self.POLL_TRIES: + logger.warning('Retrying receive... {0}/{1}'.format( + tries, self.POLL_TRIES)) + else: + break if reply is None: msg = "Timeout error contacting backend." -- cgit v1.2.3