From 687e1a87da9321b27ad966907db0f58f1c25b157 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 2 Jun 2014 15:45:06 -0500 Subject: add restore clearnet button. Closes: #5726 --- src/leap/bitmask/backend.py | 36 +++++++++----- src/leap/bitmask/gui/eip_status.py | 76 ++++++++++++++++++++++++----- src/leap/bitmask/gui/ui/eip_status.ui | 27 ++++++---- src/leap/bitmask/services/eip/conductor.py | 27 +++++++--- src/leap/bitmask/services/eip/vpnprocess.py | 21 +++++--- 5 files changed, 139 insertions(+), 48 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 4ec20be7..a18dffef 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -80,13 +80,13 @@ class ILEAPService(ILEAPComponent): Interface that every Service needs to implement """ - def start(self): + def start(self, *args, **kwargs): """ Start the service. """ pass - def stop(self): + def stop(self, *args, **kwargs): """ Stops the service. """ @@ -378,7 +378,7 @@ class EIP(object): if d is not None: d.cancel() - def _start_eip(self): + def _start_eip(self, restart=False): """ Start EIP """ @@ -404,9 +404,10 @@ class EIP(object): host, port = get_openvpn_management() self._vpn.start(eipconfig=eip_config, providerconfig=provider_config, - socket_host=host, socket_port=port) + socket_host=host, socket_port=port, + restart=restart) - def start(self): + def start(self, *args, **kwargs): """ Start the service. """ @@ -419,7 +420,7 @@ class EIP(object): return try: - self._start_eip() + self._start_eip(*args, **kwargs) except vpnprocess.OpenVPNAlreadyRunning: signaler.signal(signaler.EIP_OPENVPN_ALREADY_RUNNING) except vpnprocess.AlienOpenVPNAlreadyRunning: @@ -440,11 +441,6 @@ class EIP(object): logger.error("Unexpected problem: {0!r}".format(e)) else: logger.debug('EIP: no errors') - # TODO: are we connected here? - # kali -- no, we are not! CONNECTED should be passed only - # by the vpn observer. Currently handled by the state updater - # in eip_status - #signaler.signal(signaler.EIP_CONNECTED) def _do_stop(self, shutdown=False, restart=False): """ @@ -539,6 +535,12 @@ class EIP(object): self._signaler.signal(self._signaler.EIP_GET_INITIALIZED_PROVIDERS, filtered_domains) + def tear_fw_down(self): + """ + Tear the firewall down. + """ + self._vpn.tear_down_firewall() + def get_gateways_list(self, domain): """ Signal a list of gateways for the given provider. @@ -1181,6 +1183,7 @@ class Signaler(QtCore.QObject): eip_state_changed = QtCore.Signal(dict) eip_status_changed = QtCore.Signal(dict) eip_process_finished = QtCore.Signal(int) + eip_tear_fw_down = QtCore.Signal(object) # signals whether the needed files to start EIP exist or not eip_can_start = QtCore.Signal(object) @@ -1282,6 +1285,7 @@ class Signaler(QtCore.QObject): 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" @@ -1717,7 +1721,7 @@ class Backend(object): """ self._call_queue.put(("eip", "cancel_setup_eip", None)) - def eip_start(self): + def eip_start(self, restart=False): """ Start the EIP service. @@ -1739,7 +1743,7 @@ class Backend(object): eip_status_changed -> tuple of str (download, upload) eip_vpn_launcher_exception """ - self._call_queue.put(("eip", "start", None)) + self._call_queue.put(("eip", "start", None, restart)) def eip_stop(self, shutdown=False, restart=False, failed=False): """ @@ -1805,6 +1809,12 @@ class Backend(object): self._call_queue.put(("eip", "can_start", None, domain)) + def tear_fw_down(self): + """ + Signal the need to tear the fw down. + """ + self._call_queue.put(("eip", "tear_fw_down", None)) + def user_login(self, provider, username, password): """ Execute the whole authentication process for a user diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index e7795083..fd8b35c3 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -31,6 +31,7 @@ from leap.common.check import leap_assert_type from ui_eip_status import Ui_EIPStatus +QtDelayedCall = QtCore.QTimer.singleShot logger = logging.getLogger(__name__) @@ -66,6 +67,9 @@ class EIPStatusWidget(QtGui.QWidget): self._service_name = get_service_display_name(EIP_SERVICE) self.ui.eip_bandwidth.hide() + self.hide_fw_down_button() + self.ui.btnFwDown.clicked.connect( + self._on_fw_down_button_clicked) # Set the EIP status icons self.CONNECTING_ICON = None @@ -109,8 +113,12 @@ class EIPStatusWidget(QtGui.QWidget): signaler.eip_state_changed.connect(self.update_vpn_state) signaler.eip_status_changed.connect(self.update_vpn_status) - signaler.eip_network_unreachable.connect( - self._on_eip_network_unreachable) + + # 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) def _make_status_clickable(self): """ @@ -273,6 +281,8 @@ class EIPStatusWidget(QtGui.QWidget): Disables the start/stop button. """ self.set_startstop_enabled(False) + msg = self.tr("Encrypted Internet is starting") + self.set_eip_message(msg) @QtCore.Slot() def disable_eip_start(self): @@ -314,10 +324,18 @@ class EIPStatusWidget(QtGui.QWidget): if self.isVisible(): self._eip_status_menu.menuAction().setVisible(True) - # XXX disable (later) -------------------------- + def set_eip_message(self, message): + """ + Set the EIP Widget main message. + + :param message: the message to set in the widget + :type message: str or unicode + """ + self.ui.lblEIPMessage.setText(message) + def set_eip_status(self, status, error=False): """ - Sets the status label at the VPN stage to status + Set the status label at the VPN stage to status. :param status: status message :type status: str or unicode @@ -362,6 +380,26 @@ class EIPStatusWidget(QtGui.QWidget): self.ui.btnEipStartStop.clicked.connect( self.eipconnection.qtsigs.do_connect_signal) + def hide_fw_down_button(self): + """ + Hide firewall-down button. + """ + self.ui.btnFwDown.hide() + + def show_fw_down_button(self): + """ + Enable firewall-down button. + """ + self.ui.btnFwDown.show() + + def _on_fw_down_button_clicked(self): + """ + Raise a signal for tearing down the firewall, and hide the button + afterwards. + """ + self.eip_conductor._backend.tear_fw_down() + QtDelayedCall(50, self.hide_fw_down_button) + @QtCore.Slot(dict) def eip_stopped(self, restart=False, failed=False): """ @@ -382,7 +420,7 @@ class EIPStatusWidget(QtGui.QWidget): clear_traffic = self.tr("Traffic is being routed in the clear.") unreachable_net = self.tr("Network is unreachable.") - failed_msg = self.tr("Cannot start Encrypted Proxy.") + failed_msg = self.tr("Cannot start Encrypted Internet") if restart: msg = unreachable_net @@ -390,18 +428,19 @@ class EIPStatusWidget(QtGui.QWidget): msg = failed_msg else: msg = clear_traffic - self.ui.lblEIPMessage.setText(msg) + self.set_eip_message(msg) self.ui.lblEIPStatus.show() + self.show() def eip_failed_to_restart(self): """ Update EIP messages. """ - msg = self.tr("Could not restart Encrypted Proxy") + msg = self.tr("Could not restart Encrypted Internet") self.ui.lblEIPMessage.setText(msg) self.ui.lblEIPStatus.show() - - self.set_eip_status(self.tr("You can start the service manually.")) + self.set_eip_status(self.tr("You can launch the service manually.")) + self.show_fw_down_button() @QtCore.Slot(dict) def update_vpn_status(self, data=None): @@ -462,10 +501,15 @@ class EIPStatusWidget(QtGui.QWidget): # XXX should be handled by the state machine too. # --- is this currently being sent? self.eipconnection.qtsigs.connected_signal.emit() + self._on_eip_connected() # XXX should lookup vpn_state map in EIPConnection elif vpn_state == "AUTH": self.set_eip_status(self.tr("Authenticating...")) + # we wipe up any previous error info in the EIP message + # when we detect vpn authentication is happening + msg = self.tr("Encrypted Internet is starting") + self.set_eip_message(msg) elif vpn_state == "GET_CONFIG": self.set_eip_status(self.tr("Retrieving configuration...")) elif vpn_state == "WAIT": @@ -478,10 +522,10 @@ class EIPStatusWidget(QtGui.QWidget): # Put the following calls in Qt's event queue, otherwise # the UI won't update properly #self.send_disconnect_signal() - QtCore.QTimer.singleShot( + QtDelayedCall( 0, self.eipconnection.qtsigns.do_disconnect_signal.emit) msg = self.tr("Unable to start VPN, it's already running.") - QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg)) + QtDelayedCall(0, partial(self.set_eip_status, msg)) else: self.set_eip_status(vpn_state) @@ -524,7 +568,8 @@ class EIPStatusWidget(QtGui.QWidget): def set_provider(self, provider): self._provider = provider self.ui.lblEIPMessage.setText( - self.tr("Route traffic through: {0}").format(self._provider)) + self.tr("Routing traffic through: {0}").format( + self._provider)) def aborted(self): """ @@ -619,6 +664,13 @@ class EIPStatusWidget(QtGui.QWidget): self.aborted() + def _on_eip_connected(self): + """ + Reconnect the disconnecting signal when we are just connected, + so that we restore the disconnecting -> stop behaviour. + """ + self.eip_conductor.reconnect_stop_signal() + @QtCore.Slot() def _on_eip_network_unreachable(self): """ diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index 64821ad6..01d6b371 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -28,7 +28,7 @@ 0 - + Turn On @@ -86,7 +86,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -161,12 +161,13 @@ 0.0 KB/s + + + :/images/black/32/arrow-down.png:/images/black/32/arrow-down.png + true - - :/images/light/16/down-arrow.png - @@ -211,12 +212,13 @@ 0.0 KB/s + + + :/images/black/32/arrow-up.png:/images/black/32/arrow-up.png + true - - :/images/light/16/up-arrow.png - @@ -237,6 +239,13 @@ + + + + Allow unencrypted traffic + + + diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index 53b1fde9..3c031952 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -114,6 +114,12 @@ class EIPConductor(object): """ self.qtsigs.do_connect_signal.emit() + def tear_fw_down(self): + """ + Tear the firewall down. + """ + self._backend.tear_fw_down() + @QtCore.Slot() def _start_eip(self): """ @@ -130,6 +136,7 @@ class EIPConductor(object): else: self._eip_status.eip_pre_up() self.user_stopped_eip = False + self._eip_status.hide_fw_down_button() # 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 @@ -138,7 +145,19 @@ class EIPConductor(object): self._eip_status.is_restart = False # DO the backend call! - self._backend.eip_start() + self._backend.eip_start(restart=is_restart) + + def reconnect_stop_signal(self): + """ + Restore the original behaviour associated with the disconnecting + signal, this is, trigger a normal stop, and not a restart one. + """ + + def do_stop(*args): + self._stop_eip(restart=False) + + self.qtsigs.disconnecting_signal.disconnect() + self.qtsigs.disconnecting_signal.connect(do_stop) @QtCore.Slot() def _stop_eip(self, restart=False, failed=False): @@ -178,10 +197,6 @@ class EIPConductor(object): def do_stop(*args): self._stop_eip(restart=False) - def reconnect_stop_signal(): - self.qtsigs.disconnecting_signal.disconnect() - self.qtsigs.disconnecting_signal.connect(do_stop) - if restart: # we bypass the on_eip_disconnected here plug_restart_on_disconnected() @@ -209,7 +224,7 @@ class EIPConductor(object): # XXX needed? if restart: - QtDelayedCall(3000, reconnect_stop_signal) + QtDelayedCall(2000, self.reconnect_stop_signal) @QtCore.Slot() def _do_eip_restart(self): diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index 1de4a851..f56d464e 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -183,6 +183,8 @@ class VPN(object): kwargs['openvpn_verb'] = self._openvpn_verb kwargs['signaler'] = self._signaler + restart = kwargs.pop('restart', False) + # start the main vpn subprocess vpnproc = VPNProcess(*args, **kwargs) @@ -193,8 +195,9 @@ class VPN(object): # we try to bring the firewall up if IS_LINUX: gateways = vpnproc.getGateways() - firewall_up = self._launch_firewall(gateways) - if not firewall_up: + firewall_up = self._launch_firewall(gateways, + restart=restart) + if not restart and not firewall_up: logger.error("Could not bring firewall up, " "aborting openvpn launch.") return @@ -216,7 +219,7 @@ class VPN(object): self._pollers.extend(poll_list) self._start_pollers() - def _launch_firewall(self, gateways): + def _launch_firewall(self, gateways, restart=False): """ Launch the firewall using the privileged wrapper. @@ -231,8 +234,10 @@ class VPN(object): # XXX could check that the iptables rules are in place. BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT - exitCode = subprocess.call(["pkexec", - BM_ROOT, "firewall", "start"] + gateways) + cmd = ["pkexec", BM_ROOT, "firewall", "start"] + if restart: + cmd.append("restart") + exitCode = subprocess.call(cmd + gateways) return True if exitCode is 0 else False def is_fw_down(self): @@ -246,7 +251,7 @@ class VPN(object): fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256 return fw_is_down() - def _tear_down_firewall(self): + def tear_down_firewall(self): """ Tear the firewall down using the privileged wrapper. """ @@ -270,7 +275,7 @@ class VPN(object): # we try to tear the firewall down if IS_LINUX and self._user_stopped: - firewall_down = self._tear_down_firewall() + firewall_down = self.tear_down_firewall() if firewall_down: logger.debug("Firewall down") else: @@ -333,7 +338,7 @@ class VPN(object): self.TERMINATE_WAIT, self._kill_if_left_alive) if IS_LINUX and self._user_stopped: - firewall_down = self._tear_down_firewall() + firewall_down = self.tear_down_firewall() if firewall_down: logger.debug("Firewall down") else: -- cgit v1.2.3