summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/services
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/bitmask/services')
-rw-r--r--src/leap/bitmask/services/eip/conductor.py40
-rw-r--r--src/leap/bitmask/services/eip/darwinvpnlauncher.py4
-rw-r--r--src/leap/bitmask/services/eip/eipbootstrapper.py6
-rw-r--r--src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py2
-rw-r--r--src/leap/bitmask/services/eip/vpnlauncher.py24
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py50
-rw-r--r--src/leap/bitmask/services/mail/conductor.py6
-rw-r--r--src/leap/bitmask/services/mail/plumber.py11
-rw-r--r--src/leap/bitmask/services/soledad/soledadbootstrapper.py44
-rw-r--r--src/leap/bitmask/services/tests/test_abstractbootstrapper.py2
10 files changed, 128 insertions, 61 deletions
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
index a8821160..0ee56628 100644
--- a/src/leap/bitmask/services/eip/conductor.py
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -16,6 +16,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
EIP Conductor module.
+
+This handles Qt Signals and triggers the calls to the backend,
+where the VPNProcess has been initialized.
"""
import logging
@@ -33,7 +36,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 +49,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 +80,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)
@@ -89,7 +93,7 @@ class EIPConductor(object):
def start_eip_machine(self, action):
"""
- Initializes and starts the EIP state machine.
+ Initialize and start the EIP state machine.
Needs the reference to the eip_status widget not to be empty.
:action: QtAction
@@ -123,8 +127,12 @@ class EIPConductor(object):
@QtCore.Slot()
def _start_eip(self):
"""
- Starts EIP.
+ Start EIP.
+
+ This set a couple of status flags and calls the start procedure in the
+ backend.
"""
+ # TODO status should be kept in a singleton in the backend.
st = self._eip_status
is_restart = st and st.is_restart
@@ -136,6 +144,7 @@ class EIPConductor(object):
else:
self._eip_status.eip_pre_up()
self.user_stopped_eip = False
+ self.cancelled = False
self._eip_status.hide_fw_down_button()
# Until we set an option in the preferences window, we'll assume that
@@ -174,6 +183,9 @@ class EIPConductor(object):
:param failed: whether this is the final step of a retry sequence
:type failed: bool
"""
+ # XXX we should NOT keep status in the widget, but we do for a series
+ # of hacks related to restarts. All status should be kept in a backend
+ # object, widgets should be just widgets.
self._eip_status.is_restart = restart
self.user_stopped_eip = not restart and not failed
@@ -201,7 +213,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)
@@ -266,7 +278,7 @@ class EIPConductor(object):
TRIGGERS:
Signaler.eip_process_finished
- Triggered when the EIP/VPN process finishes to set the UI
+ Triggered when the EIP/VPN process finishes, in order to set the UI
accordingly.
Ideally we would have the right exit code here,
@@ -300,19 +312,27 @@ 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 not self.user_stopped_eip:
+ # if exitCode != 0 and not self.user_stopped_eip:
+
+ if not self.user_stopped_eip and not self.cancelled:
+ error = True
eip_status_label = self._eip_status.tr(
"{0} finished in an unexpected manner!")
eip_status_label = eip_status_label.format(self.eip_name)
- self._eip_status.eip_stopped()
self._eip_status.set_eip_status_icon("error")
self._eip_status.set_eip_status(eip_status_label,
- error=True)
+ error=error)
+ self._eip_status.eip_stopped()
signal = self.qtsigs.connection_died_signal
self._eip_status.show_fw_down_button()
self._eip_status.eip_failed_to_connect()
+ if self.cancelled:
+ signal = self.qtsigs.connection_aborted_signal
+ self._eip_status.set_eip_status_icon("error")
+ self._eip_status.eip_stopped()
+ self._eip_status.set_eip_status("", error=False)
+
if exitCode == 0 and IS_MAC:
# XXX remove this warning after I fix cocoasudo.
logger.warning("The above exit code MIGHT BE WRONG.")
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/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/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 0731bee3..72e19413 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]
@@ -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
@@ -175,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 b54f2925..c7159a93 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())
@@ -202,7 +202,24 @@ class VPN(object):
"aborting openvpn launch.")
return
- cmd = vpnproc.getCommand()
+ # FIXME it would be good to document where the
+ # errors here are catched, since we currently handle them
+ # at the frontend layer. This *should* move to be handled entirely
+ # in the backend.
+ # exception is indeed technically catched in backend, then converted
+ # into a signal, that is catched in the eip_status widget in the
+ # frontend, and converted into a signal to abort the connection that is
+ # sent to the backend again.
+
+ # the whole exception catching should be done in the backend, without
+ # the ping-pong to the frontend, and without adding any logical checks
+ # in the frontend. We should just communicate UI changes to frontend,
+ # and abstract us away from anything else.
+ try:
+ cmd = vpnproc.getCommand()
+ except Exception:
+ logger.error("Error while getting vpn command...")
+ raise
env = os.environ
for key, val in vpnproc.vpn_env.items():
env[key] = val
@@ -255,11 +272,26 @@ 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"])
return True if exitCode is 0 else False
+ def bitmask_root_vpn_down(self):
+ """
+ Bring openvpn 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, "openvpn", "stop"])
+ return True if exitCode is 0 else False
+
def _kill_if_left_alive(self, tries=0):
"""
Check if the process is still alive, and send a
@@ -594,7 +626,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 +664,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):
@@ -814,7 +846,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
@@ -869,7 +901,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/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):
"""
diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py
index c16a1fed..1af65c5d 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
@@ -83,7 +83,8 @@ def initialize_soledad(uuid, email, passwd,
secrets,
localdb,
server_url,
- cert_file)
+ cert_file,
+ defer_encryption=True)
return soledad
@@ -113,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))
@@ -231,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 db12fd80..c4e43bfe 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,12 +133,15 @@ 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)
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
@@ -181,17 +185,16 @@ 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
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):
"""
@@ -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:
@@ -379,9 +390,10 @@ 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
logger.exception("Unhandled error while syncing "
"soledad: %r" % (e,))
break
@@ -423,7 +435,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 +461,10 @@ class SoledadBootstrapper(AbstractBootstrapper):
Raises SoledadSyncError if not successful.
"""
try:
- self._soledad.sync()
+ 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,))
raise SoledadSyncError("Failed to sync soledad")
@@ -633,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()
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
#