summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/gui
diff options
context:
space:
mode:
authorIvan Alejandro <ivanalejandro0@gmail.com>2014-03-27 17:16:04 -0300
committerIvan Alejandro <ivanalejandro0@gmail.com>2014-04-15 15:00:08 -0300
commita73c432400eb6a614706fc615a505ed78d4031e3 (patch)
treea9fb74db34aae253c1b63cb3a555cea70ace55db /src/leap/bitmask/gui
parent8e492fe37168e2e6874684e422376f2a43b4a4a4 (diff)
Move EIP to the backend.
- Add backend eip management - Connect gui with new eip signals - remove old unused code - remove Qt dependency from backend services. - use Signaler to emit status/state changes from openvpn
Diffstat (limited to 'src/leap/bitmask/gui')
-rw-r--r--src/leap/bitmask/gui/eip_status.py55
-rw-r--r--src/leap/bitmask/gui/mainwindow.py297
2 files changed, 160 insertions, 192 deletions
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index 19942d9d..f24d87c7 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -25,7 +25,6 @@ from functools import partial
from PySide import QtCore, QtGui
from leap.bitmask.services.eip.connection import EIPConnection
-from leap.bitmask.services.eip.vpnprocess import VPNManager
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
@@ -99,7 +98,7 @@ class EIPStatusWidget(QtGui.QWidget):
status figures.
"""
self.DISPLAY_TRAFFIC_RATES = not self.DISPLAY_TRAFFIC_RATES
- self.update_vpn_status(None) # refresh
+ self.update_vpn_status() # refresh
def _set_traffic_rates(self):
"""
@@ -117,7 +116,7 @@ class EIPStatusWidget(QtGui.QWidget):
"""
self._up_rate.reset()
self._down_rate.reset()
- self.update_vpn_status(None)
+ self.update_vpn_status()
def _update_traffic_rates(self, up, down):
"""
@@ -348,23 +347,26 @@ class EIPStatusWidget(QtGui.QWidget):
self.tr("Traffic is being routed in the clear"))
self.ui.lblEIPStatus.show()
- def update_vpn_status(self, data):
+ def update_vpn_status(self, data=None):
"""
SLOT
- TRIGGER: VPN.status_changed
+ TRIGGER: Signaler.eip_status_changed
- Updates the download/upload labels based on the data provided
- by the VPN thread.
+ Updates the download/upload labels based on the data provided by the
+ VPN thread.
+ If data is None, we just will refresh the display based on the previous
+ data.
:param data: a dictionary with the tcp/udp write and read totals.
- If data is None, we just will refresh the display based
- on the previous data.
:type data: dict
"""
- if data:
- upload = float(data[VPNManager.TCPUDP_WRITE_KEY] or "0")
- download = float(data[VPNManager.TCPUDP_READ_KEY] or "0")
- self._update_traffic_rates(upload, download)
+ if data is not None:
+ try:
+ upload, download = map(float, data)
+ self._update_traffic_rates(upload, download)
+ except Exception:
+ # discard invalid data
+ return
if self.DISPLAY_TRAFFIC_RATES:
uprate, downrate = self._get_traffic_rates()
@@ -379,39 +381,38 @@ class EIPStatusWidget(QtGui.QWidget):
self.ui.btnUpload.setText(upload_str)
self.ui.btnDownload.setText(download_str)
- def update_vpn_state(self, data):
+ def update_vpn_state(self, vpn_state):
"""
SLOT
- TRIGGER: VPN.state_changed
+ TRIGGER: Signaler.eip_state_changed
Updates the displayed VPN state based on the data provided by
the VPN thread.
Emits:
- If the status is connected, we emit EIPConnection.qtsigs.
+ If the vpn_state is connected, we emit EIPConnection.qtsigs.
connected_signal
"""
- status = data[VPNManager.STATUS_STEP_KEY]
- self.set_eip_status_icon(status)
- if status == "CONNECTED":
+ self.set_eip_status_icon(vpn_state)
+ if vpn_state == "CONNECTED":
self.ui.eip_bandwidth.show()
self.ui.lblEIPStatus.hide()
# XXX should be handled by the state machine too.
self.eip_connection_connected.emit()
- # XXX should lookup status map in EIPConnection
- elif status == "AUTH":
+ # XXX should lookup vpn_state map in EIPConnection
+ elif vpn_state == "AUTH":
self.set_eip_status(self.tr("Authenticating..."))
- elif status == "GET_CONFIG":
+ elif vpn_state == "GET_CONFIG":
self.set_eip_status(self.tr("Retrieving configuration..."))
- elif status == "WAIT":
+ elif vpn_state == "WAIT":
self.set_eip_status(self.tr("Waiting to start..."))
- elif status == "ASSIGN_IP":
+ elif vpn_state == "ASSIGN_IP":
self.set_eip_status(self.tr("Assigning IP"))
- elif status == "RECONNECTING":
+ elif vpn_state == "RECONNECTING":
self.set_eip_status(self.tr("Reconnecting..."))
- elif status == "ALREADYRUNNING":
+ elif vpn_state == "ALREADYRUNNING":
# Put the following calls in Qt's event queue, otherwise
# the UI won't update properly
QtCore.QTimer.singleShot(
@@ -419,7 +420,7 @@ class EIPStatusWidget(QtGui.QWidget):
msg = self.tr("Unable to start VPN, it's already running.")
QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg))
else:
- self.set_eip_status(status)
+ self.set_eip_status(vpn_state)
def set_eip_icon(self, icon):
"""
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 6eaf2dfb..985ad945 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -33,16 +33,16 @@ from leap.bitmask.config import flags
from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.config.providerconfig import ProviderConfig
-from leap.bitmask.gui.loggerwindow import LoggerWindow
+from leap.bitmask.gui import statemachines
from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement
-from leap.bitmask.gui.login import LoginWidget
-from leap.bitmask.gui.preferenceswindow import PreferencesWindow
from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow
-from leap.bitmask.gui import statemachines
from leap.bitmask.gui.eip_status import EIPStatusWidget
+from leap.bitmask.gui.loggerwindow import LoggerWindow
+from leap.bitmask.gui.login import LoginWidget
from leap.bitmask.gui.mail_status import MailStatusWidget
-from leap.bitmask.gui.wizard import Wizard
+from leap.bitmask.gui.preferenceswindow import PreferencesWindow
from leap.bitmask.gui.systray import SysTray
+from leap.bitmask.gui.wizard import Wizard
from leap.bitmask import provider
from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX
@@ -55,19 +55,7 @@ from leap.bitmask.services import get_service_display_name
from leap.bitmask.services.mail import conductor as mail_conductor
from leap.bitmask.services import EIP_SERVICE, MX_SERVICE
-from leap.bitmask.services.eip import eipconfig
-from leap.bitmask.services.eip import get_openvpn_management
from leap.bitmask.services.eip.connection import EIPConnection
-from leap.bitmask.services.eip.vpnprocess import VPN
-from leap.bitmask.services.eip.vpnprocess import OpenVPNAlreadyRunning
-from leap.bitmask.services.eip.vpnprocess import AlienOpenVPNAlreadyRunning
-
-from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException
-from leap.bitmask.services.eip.vpnlauncher import OpenVPNNotFoundException
-from leap.bitmask.services.eip.linuxvpnlauncher import EIPNoPkexecAvailable
-from leap.bitmask.services.eip.linuxvpnlauncher import \
- EIPNoPolkitAuthAgentAvailable
-from leap.bitmask.services.eip.darwinvpnlauncher import EIPNoTunKextLoaded
from leap.bitmask.services.soledad.soledadbootstrapper import \
SoledadBootstrapper
@@ -94,11 +82,6 @@ class MainWindow(QtGui.QMainWindow):
"""
Main window for login and presenting status updates to the user
"""
-
- # StackedWidget indexes
- LOGIN_INDEX = 0
- EIP_STATUS_INDEX = 1
-
# Signals
eip_needs_login = QtCore.Signal([])
offline_mode_bypass_login = QtCore.Signal([])
@@ -117,9 +100,7 @@ class MainWindow(QtGui.QMainWindow):
# We give each service some time to come to a halt before forcing quit
SERVICE_STOP_TIMEOUT = 20
- def __init__(self, quit_callback,
- bypass_checks=False,
- start_hidden=False):
+ def __init__(self, quit_callback, bypass_checks=False, start_hidden=False):
"""
Constructor for the client main window
@@ -127,9 +108,8 @@ class MainWindow(QtGui.QMainWindow):
the application.
:type quit_callback: callable
- :param bypass_checks: Set to true if the app should bypass
- first round of checks for CA
- certificates at bootstrap
+ :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.
@@ -188,21 +168,19 @@ class MainWindow(QtGui.QMainWindow):
# XXX this should be handled by EIP Conductor
self._eip_connection.qtsigs.connecting_signal.connect(
- self._start_eip)
+ self._start_EIP)
self._eip_connection.qtsigs.disconnecting_signal.connect(
self._stop_eip)
self._eip_status.eip_connection_connected.connect(
- self._on_eip_connected)
+ self._on_eip_connection_connected)
self._eip_status.eip_connection_connected.connect(
self._maybe_run_soledad_setup_checks)
self.offline_mode_bypass_login.connect(
self._maybe_run_soledad_setup_checks)
- self.eip_needs_login.connect(
- self._eip_status.disable_eip_start)
- self.eip_needs_login.connect(
- self._disable_eip_start_action)
+ self.eip_needs_login.connect(self._eip_status.disable_eip_start)
+ self.eip_needs_login.connect(self._disable_eip_start_action)
# This is loaded only once, there's a bug when doing that more
# than once
@@ -212,7 +190,6 @@ class MainWindow(QtGui.QMainWindow):
# Used for automatic start of EIP
self._provisional_provider_config = ProviderConfig()
- self._eip_config = eipconfig.EIPConfig()
self._already_started_eip = False
self._already_started_soledad = False
@@ -225,22 +202,6 @@ class MainWindow(QtGui.QMainWindow):
self._backend_connected_signals = {}
self._backend_connect()
- self._vpn = VPN()
-
- # connect vpn process signals
- self._vpn.qtsigs.state_changed.connect(
- self._eip_status.update_vpn_state)
- self._vpn.qtsigs.status_changed.connect(
- self._eip_status.update_vpn_status)
- self._vpn.qtsigs.process_finished.connect(
- self._eip_finished)
- self._vpn.qtsigs.network_unreachable.connect(
- self._on_eip_network_unreachable)
- self._vpn.qtsigs.process_restart_tls.connect(
- self._do_eip_restart)
- self._vpn.qtsigs.process_restart_ping.connect(
- self._do_eip_restart)
-
self._soledad_bootstrapper = SoledadBootstrapper()
self._soledad_bootstrapper.download_config.connect(
self._soledad_intermediate_stage)
@@ -419,6 +380,7 @@ class MainWindow(QtGui.QMainWindow):
self._connect_and_track(sig.prov_cancelled_setup,
self._set_login_cancelled)
+ # Login signals
self._connect_and_track(sig.srp_auth_ok, self._authentication_finished)
auth_error = (
@@ -442,16 +404,44 @@ class MainWindow(QtGui.QMainWindow):
self._connect_and_track(sig.srp_auth_bad_user_or_password,
auth_bad_user_or_password)
+ # Logout signals
self._connect_and_track(sig.srp_logout_ok, self._logout_ok)
self._connect_and_track(sig.srp_logout_error, self._logout_error)
self._connect_and_track(sig.srp_not_logged_in_error,
self._not_logged_in_error)
+ # EIP bootstrap signals
+ self._connect_and_track(sig.eip_download_config,
+ self._eip_intermediate_stage)
+ self._connect_and_track(sig.eip_download_client_certificate,
+ self._finish_eip_bootstrap)
+
# We don't want to disconnect some signals so don't track them:
sig.prov_unsupported_client.connect(self._needs_update)
sig.prov_unsupported_api.connect(self._incompatible_api)
+ # EIP start signals
+ sig.eip_openvpn_already_running.connect(
+ self._on_eip_openvpn_already_running)
+ sig.eip_alien_openvpn_already_running.connect(
+ self._on_eip_alien_openvpn_already_running)
+ sig.eip_openvpn_not_found_error.connect(
+ self._on_eip_openvpn_not_found_error)
+ sig.eip_vpn_launcher_exception.connect(
+ self._on_eip_vpn_launcher_exception)
+ sig.eip_no_polkit_agent_error.connect(
+ self._on_eip_no_polkit_agent_error)
+ sig.eip_no_pkexec_error.connect(self._on_eip_no_pkexec_error)
+ sig.eip_no_tun_kext_error.connect(self._on_eip_no_tun_kext_error)
+
+ sig.eip_state_changed.connect(self._eip_status.update_vpn_state)
+ sig.eip_status_changed.connect(self._eip_status.update_vpn_status)
+ sig.eip_process_finished.connect(self._eip_finished)
+ sig.eip_network_unreachable.connect(self._on_eip_network_unreachable)
+ sig.eip_process_restart_tls.connect(self._do_eip_restart)
+ sig.eip_process_restart_ping.connect(self._do_eip_restart)
+
def _disconnect_and_untrack(self):
"""
Helper to disconnect the tracked signals.
@@ -1495,7 +1485,7 @@ class MainWindow(QtGui.QMainWindow):
self._action_eip_startstop.setEnabled(True)
@QtCore.Slot()
- def _on_eip_connected(self):
+ def _on_eip_connection_connected(self):
"""
SLOT
TRIGGERS:
@@ -1585,114 +1575,101 @@ class MainWindow(QtGui.QMainWindow):
(default_provider,))
@QtCore.Slot()
- def _start_eip(self):
+ def _start_EIP(self):
"""
- SLOT
- TRIGGERS:
- self._eip_connection.qtsigs.do_connect_signal
- (via state machine)
- or called from _finish_eip_bootstrap
-
Starts EIP
"""
- provider_config = self._get_best_provider_config()
- provider = provider_config.get_domain()
self._eip_status.eip_pre_up()
self.user_stopped_eip = False
- # until we set an option in the preferences window,
- # we'll assume that by default we try to autostart.
- # If we switch it off manually, it won't try the next
- # time.
+ # Until we set an option in the preferences window, we'll assume that
+ # by default we try to autostart. If we switch it off manually, it
+ # won't try the next time.
self._settings.set_autostart_eip(True)
- loaded = eipconfig.load_eipconfig_if_needed(
- provider_config, self._eip_config, provider)
+ self._backend.start_eip()
- if not loaded:
- eip_status_label = self.tr("Could not load {0} configuration.")
- eip_status_label = eip_status_label.format(self._eip_name)
- self._eip_status.set_eip_status(eip_status_label, error=True)
- # signal connection aborted to state machine
- qtsigs = self._eip_connection.qtsigs
- qtsigs.connection_aborted_signal.emit()
- logger.error("Tried to start EIP but cannot find any "
- "available provider!")
- return
+ def _on_eip_connection_aborted(self):
+ """
+ SLOT
+ TRIGGERS:
+ Signaler.eip_connection_aborted
+ """
+ logger.error("Tried to start EIP but cannot find any "
+ "available provider!")
- try:
- # XXX move this to EIPConductor
- host, port = get_openvpn_management()
- self._vpn.start(eipconfig=self._eip_config,
- providerconfig=provider_config,
- socket_host=host,
- socket_port=port)
- self._settings.set_defaultprovider(provider)
-
- # XXX move to the state machine too
- self._eip_status.set_provider(provider)
-
- # TODO refactor exceptions so they provide translatable
- # usef-facing messages.
- except EIPNoPolkitAuthAgentAvailable:
- self._eip_status.set_eip_status(
- # XXX this should change to polkit-kde where
- # applicable.
- self.tr("We could not find any "
- "authentication "
- "agent in your system.<br/>"
- "Make sure you have "
- "<b>polkit-gnome-authentication-"
- "agent-1</b> "
- "running and try again."),
- error=True)
- self._set_eipstatus_off()
- except EIPNoTunKextLoaded:
- self._eip_status.set_eip_status(
- self.tr("{0} cannot be started because "
- "the tuntap extension is not installed properly "
- "in your system.").format(self._eip_name))
- self._set_eipstatus_off()
- except EIPNoPkexecAvailable:
- self._eip_status.set_eip_status(
- self.tr("We could not find <b>pkexec</b> "
- "in your system."),
- error=True)
- self._set_eipstatus_off()
- except OpenVPNNotFoundException:
- self._eip_status.set_eip_status(
- self.tr("We could not find openvpn binary."),
- error=True)
- self._set_eipstatus_off()
- except OpenVPNAlreadyRunning as e:
- self._eip_status.set_eip_status(
- self.tr("Another openvpn instance is already running, and "
- "could not be stopped."),
- error=True)
- self._set_eipstatus_off()
- except AlienOpenVPNAlreadyRunning as e:
- self._eip_status.set_eip_status(
- self.tr("Another openvpn instance is already running, and "
- "could not be stopped because it was not launched by "
- "Bitmask. Please stop it and try again."),
- error=True)
- self._set_eipstatus_off()
- except VPNLauncherException as e:
- # XXX We should implement again translatable exceptions so
- # we can pass a translatable string to the panel (usermessage attr)
- self._eip_status.set_eip_status("%s" % (e,), error=True)
- self._set_eipstatus_off()
- else:
- self._already_started_eip = True
+ eip_status_label = self.tr("Could not load {0} configuration.")
+ eip_status_label = eip_status_label.format(self._eip_name)
+ self._eip_status.set_eip_status(eip_status_label, error=True)
+
+ # signal connection_aborted to state machine:
+ qtsigs = self._eip_connection.qtsigs
+ qtsigs.connection_aborted_signal.emit()
+
+ def _on_eip_openvpn_already_running(self):
+ self._eip_status.set_eip_status(
+ self.tr("Another openvpn instance is already running, and "
+ "could not be stopped."),
+ error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_alien_openvpn_already_running(self):
+ self._eip_status.set_eip_status(
+ self.tr("Another openvpn instance is already running, and "
+ "could not be stopped because it was not launched by "
+ "Bitmask. Please stop it and try again."),
+ error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_openvpn_not_found_error(self):
+ self._eip_status.set_eip_status(
+ self.tr("We could not find openvpn binary."),
+ error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_vpn_launcher_exception(self):
+ # XXX We should implement again translatable exceptions so
+ # we can pass a translatable string to the panel (usermessage attr)
+ self._eip_status.set_eip_status("VPN Launcher error.", error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_no_polkit_agent_error(self):
+ self._eip_status.set_eip_status(
+ # XXX this should change to polkit-kde where
+ # applicable.
+ self.tr("We could not find any authentication agent in your "
+ "system.<br/>Make sure you have"
+ "<b>polkit-gnome-authentication-agent-1</b> running and"
+ "try again."),
+ error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_no_pkexec_error(self):
+ self._eip_status.set_eip_status(
+ self.tr("We could not find <b>pkexec</b> in your system."),
+ error=True)
+ self._set_eipstatus_off()
+
+ def _on_eip_no_tun_kext_error(self):
+ self._eip_status.set_eip_status(
+ self.tr("{0} cannot be started because the tuntap extension is "
+ "not installed properly in your "
+ "system.").format(self._eip_name))
+ self._set_eipstatus_off()
+
+ def _on_eip_connected(self):
+ # XXX move to the state machine too
+ self._eip_status.set_provider(provider)
+
+ self._settings.set_defaultprovider(provider)
+ self._already_started_eip = True
@QtCore.Slot()
def _stop_eip(self):
"""
SLOT
TRIGGERS:
- self._eip_connection.qtsigs.do_disconnect_signal
- (via state machine)
- or called from _eip_finished
+ self._eip_connection.qtsigs.do_disconnect_signal (via state machine)
Stops vpn process and makes gui adjustments to reflect
the change of state.
@@ -1701,7 +1678,7 @@ class MainWindow(QtGui.QMainWindow):
:type abnormal: bool
"""
self.user_stopped_eip = True
- self._vpn.terminate()
+ self._backend.stop_eip()
self._set_eipstatus_off(False)
self._already_started_eip = False
@@ -1742,7 +1719,7 @@ class MainWindow(QtGui.QMainWindow):
# for some reason, emitting the do_disconnect/do_connect
# signals hangs the UI.
self._stop_eip()
- QtCore.QTimer.singleShot(2000, self._start_eip)
+ QtCore.QTimer.singleShot(2000, self._start_EIP)
def _set_eipstatus_off(self, error=True):
"""
@@ -1756,7 +1733,7 @@ class MainWindow(QtGui.QMainWindow):
"""
SLOT
TRIGGERS:
- self._vpn.process_finished
+ Signaler.eip_process_finished
Triggered when the EIP/VPN process finishes to set the UI
accordingly.
@@ -1792,8 +1769,8 @@ class MainWindow(QtGui.QMainWindow):
"because you did not authenticate properly.")
eip_status_label = eip_status_label.format(self._eip_name)
self._eip_status.set_eip_status(eip_status_label, error=True)
- self._vpn.killit()
signal = qtsigs.connection_aborted_signal
+ self._backend.terminate_eip()
elif exitCode != 0 or not self.user_stopped_eip:
eip_status_label = self.tr("{0} finished in an unexpected manner!")
@@ -1853,7 +1830,6 @@ class MainWindow(QtGui.QMainWindow):
Starts the VPN thread if the eip configuration is properly
loaded
"""
- leap_assert(self._eip_config, "We need an eip config!")
passed = data[self._backend.PASSED_KEY]
if not passed:
@@ -1863,20 +1839,8 @@ class MainWindow(QtGui.QMainWindow):
self._already_started_eip = False
return
- provider_config = self._get_best_provider_config()
- domain = provider_config.get_domain()
-
- # XXX move check to _start_eip ?
- loaded = eipconfig.load_eipconfig_if_needed(
- provider_config, self._eip_config, domain)
-
- if loaded:
- # DO START EIP Connection!
- self._eip_connection.qtsigs.do_connect_signal.emit()
- else:
- eip_status_label = self.tr("Could not load {0} configuration.")
- eip_status_label = eip_status_label.format(self._eip_name)
- self._eip_status.set_eip_status(eip_status_label, error=True)
+ # DO START EIP Connection!
+ self._eip_connection.qtsigs.do_connect_signal.emit()
def _eip_intermediate_stage(self, data):
# TODO missing param
@@ -2051,7 +2015,7 @@ class MainWindow(QtGui.QMainWindow):
logger.error("No instance of soledad was found.")
logger.debug('Terminating vpn')
- self._vpn.terminate(shutdown=True)
+ self._backend.stop_eip(shutdown=True)
self._cancel_ongoing_defers()
@@ -2079,8 +2043,11 @@ class MainWindow(QtGui.QMainWindow):
# Set this in case that the app is hidden
QtGui.QApplication.setQuitOnLastWindowClosed(True)
- self._backend.stop()
self._cleanup_and_quit()
+
+ # We queue the call to stop since we need to wait until EIP is stopped.
+ # Otherwise we may exit leaving an unmanaged openvpn process.
+ reactor.callLater(0, self._backend.stop)
self._really_quit = True
if self._wizard: