diff options
author | Tomás Touceda <chiiph@leap.se> | 2013-06-24 11:42:56 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2013-06-24 11:42:56 -0300 |
commit | a628dcbc372161d979548c09a3cb22f6878c8bd1 (patch) | |
tree | 1bf7d292dd7b0b76c2825ae8cd504f717da1e16b /src | |
parent | 071cbe0e31f73ad774551a5d5474be9edb7a9c5c (diff) | |
parent | 19c90e02a65d1d6fe30e6915cd2a9440878aef83 (diff) |
Merge remote-tracking branch 'kali/feature/better-vpn-control' into develop
Diffstat (limited to 'src')
-rw-r--r-- | src/leap/gui/mainwindow.py | 85 | ||||
-rw-r--r-- | src/leap/gui/statuspanel.py | 46 | ||||
-rw-r--r-- | src/leap/gui/ui/statuspanel.ui | 346 | ||||
-rw-r--r-- | src/leap/services/eip/vpnlaunchers.py | 2 | ||||
-rw-r--r-- | src/leap/services/eip/vpnprocess.py | 30 |
5 files changed, 310 insertions, 199 deletions
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py index 9dc1e006..94343292 100644 --- a/src/leap/gui/mainwindow.py +++ b/src/leap/gui/mainwindow.py @@ -90,6 +90,9 @@ class MainWindow(QtGui.QMainWindow): new_updates = QtCore.Signal(object) raise_window = QtCore.Signal([]) + # We use this flag to detect abnormal terminations + user_stopped_eip = False + def __init__(self, quit_callback, standalone=False, bypass_checks=False): """ @@ -695,7 +698,7 @@ class MainWindow(QtGui.QMainWindow): download_if_needed=True) else: self._login_widget.set_status( - self.tr("Could not load provider configuration")) + self.tr("Could not load provider configuration.")) self._login_widget.set_enabled(True) else: self._login_widget.set_status( @@ -950,6 +953,8 @@ class MainWindow(QtGui.QMainWindow): Starts EIP """ + self._status_panel.eip_pre_up() + self.user_stopped_eip = False provider_config = self._get_best_provider_config() try: @@ -977,7 +982,9 @@ class MainWindow(QtGui.QMainWindow): self._action_eip_startstop.triggered.connect( self._stop_eip) except EIPNoPolkitAuthAgentAvailable: - self._status_panel.set_eip_status( + self._status_panel.set_global_status( + # XXX this should change to polkit-kde where + # applicable. self.tr("We could not find any " "authentication " "agent in your system.<br/>" @@ -986,30 +993,44 @@ class MainWindow(QtGui.QMainWindow): "agent-1</b> " "running and try again."), error=True) + self._set_eipstatus_off() except EIPNoPkexecAvailable: - self._status_panel.set_eip_status( + self._status_panel.set_global_status( self.tr("We could not find <b>pkexec</b> " "in your system."), error=True) + self._set_eipstatus_off() except OpenVPNNotFoundException: - self._status_panel.set_eip_status( - self.tr("We couldn't find openvpn binary"), + self._status_panel.set_global_status( + self.tr("We could not find openvpn binary."), error=True) + self._set_eipstatus_off() except VPNLauncherException as e: - self._status_panel.set_eip_status("%s" % (e,), error=True) + self._status_panel.set_gloal_status("%s" % (e,), error=True) + self._set_eipstatus_off() else: self._already_started_eip = True + def _set_eipstatus_off(self): + """ + Sets eip status to off + """ + self._status_panel.set_eip_status(self.tr("OFF"), error=True) self._status_panel.set_startstop_enabled(True) - def _stop_eip(self): + def _stop_eip(self, abnormal=False): """ Stops vpn process and makes gui adjustments to reflect the change of state. + + :param abnormal: whether this was an abnormal termination. + :type abnormal: bool + "" """ + self.user_stopped_eip = True self._vpn.terminate() - self._status_panel.set_eip_status(self.tr("Off")) + self._status_panel.set_eip_status(self.tr("OFF")) self._status_panel.set_eip_status_icon("error") self._status_panel.eip_stopped() self._action_eip_startstop.setText(self.tr("Turn ON")) @@ -1022,6 +1043,8 @@ class MainWindow(QtGui.QMainWindow): self._status_panel.set_provider( "%s@%s" % (self._logged_user, self._get_best_provider_config().get_domain())) + if abnormal: + self._status_panel.set_startstop_enabled(True) def _get_best_provider_config(self): """ @@ -1042,7 +1065,7 @@ class MainWindow(QtGui.QMainWindow): elif self._provisional_provider_config.loaded(): provider_config = self._provisional_provider_config else: - leap_assert(False, "We couldn't find any usable ProviderConfig") + leap_assert(False, "We could not find any usable ProviderConfig.") return provider_config @@ -1097,7 +1120,8 @@ class MainWindow(QtGui.QMainWindow): else: if data[self._eip_bootstrapper.PASSED_KEY]: self._status_panel.set_eip_status( - self.tr("Could not load Encrypted Internet Configuration"), + self.tr("Could not load Encrypted Internet " + "Configuration."), error=True) else: self._status_panel.set_eip_status( @@ -1173,10 +1197,43 @@ class MainWindow(QtGui.QMainWindow): self._vpn.process_finished Triggered when the EIP/VPN process finishes to set the UI - accordingly - """ - logger.debug("Finished VPN with exitCode %s" % (exitCode,)) - self._stop_eip() + accordingly. + """ + logger.info("VPN process finished with exitCode %s..." + % (exitCode,)) + + # Ideally we would have the right exit code here, + # but the use of different wrappers (pkexec, cocoasudo) swallows + # the openvpn exit code so we get zero exit in some cases where we + # shouldn't. As a workaround we just use a flag to indicate + # a purposeful switch off, and mark everything else as unexpected. + + # In the near future we should trigger a native notification from here, + # since the user really really wants to know she is unprotected asap. + # And the right thing to do will be to fail-close. + + # TODO we should have a way of parsing the latest lines in the vpn + # log buffer so we can have a more precise idea of which type + # of error did we have (server side, local problem, etc) + abnormal = True + + # XXX check if these exitCodes are pkexec/cocoasudo specific + if exitCode in (126, 127): + self._status_panel.set_global_status( + self.tr("Encrypted Internet could not be launched " + "because you did not authenticate properly."), + error=True) + self._vpn.killit() + elif exitCode != 0 or not self.user_stopped_eip: + self._status_panel.set_global_status( + self.tr("Encrypted Internet finished in an " + "unexpected manner!"), error=True) + else: + abnormal = False + if exitCode == 0: + # XXX remove this warning after I fix cocoasudo. + logger.warning("The above exit code MIGHT BE WRONG.") + self._stop_eip(abnormal) def _on_raise_window_event(self, req): """ diff --git a/src/leap/gui/statuspanel.py b/src/leap/gui/statuspanel.py index 62a22725..3e5a5093 100644 --- a/src/leap/gui/statuspanel.py +++ b/src/leap/gui/statuspanel.py @@ -52,6 +52,8 @@ class StatusPanelWidget(QtGui.QWidget): self.ui.btnEipStartStop.clicked.connect( self.start_eip) + self.hide_status_box() + # Set the EIP status icons self.CONNECTING_ICON = None self.CONNECTED_ICON = None @@ -95,7 +97,7 @@ class StatusPanelWidget(QtGui.QWidget): def set_systray(self, systray): """ - Sets the systray object to use + Sets the systray object to use. :param systray: Systray object :type systray: QtGui.QSystemTrayIcon @@ -105,7 +107,7 @@ class StatusPanelWidget(QtGui.QWidget): def set_action_eip_status(self, action_eip_status): """ - Sets the action_eip_status to use + Sets the action_eip_status to use. :param action_eip_status: action_eip_status to be used :type action_eip_status: QtGui.QAction @@ -113,6 +115,28 @@ class StatusPanelWidget(QtGui.QWidget): leap_assert_type(action_eip_status, QtGui.QAction) self._action_eip_status = action_eip_status + def set_global_status(self, status, error=False): + """ + Sets the global status label. + + :param status: status message + :type status: str or unicode + :param error: if the status is an erroneous one, then set this + to True + :type error: bool + """ + leap_assert_type(error, bool) + if error: + status = "<font color='red'><b>%s</b></font>" % (status,) + self.ui.lblGlobalStatus.setText(status) + self.ui.globalStatusBox.show() + + def hide_status_box(self): + """ + Hide global status box. + """ + self.ui.globalStatusBox.hide() + def set_eip_status(self, status, error=False): """ Sets the status label at the VPN stage to status @@ -140,6 +164,14 @@ class StatusPanelWidget(QtGui.QWidget): leap_assert_type(value, bool) self.ui.btnEipStartStop.setEnabled(value) + def eip_pre_up(self): + """ + Triggered when the app activates eip. + Hides the status box and disables the start/stop button. + """ + self.hide_status_box() + self.set_startstop_enabled(False) + def eip_started(self): """ Sets the state of the widget to how it should look after EIP @@ -196,12 +228,14 @@ class StatusPanelWidget(QtGui.QWidget): """ status = data[VPNManager.STATUS_STEP_KEY] self.set_eip_status_icon(status) - if status == "AUTH": + if status == "CONNECTED": + self.set_eip_status(self.tr("ON")) + # Only now we can properly enable the button. + self.set_startstop_enabled(True) + elif status == "AUTH": self.set_eip_status(self.tr("Authenticating...")) elif status == "GET_CONFIG": self.set_eip_status(self.tr("Retrieving configuration...")) - elif status == "CONNECTED": - self.set_eip_status(self.tr("On")) elif status == "WAIT": self.set_eip_status(self.tr("Waiting to start...")) elif status == "ASSIGN_IP": @@ -210,7 +244,7 @@ class StatusPanelWidget(QtGui.QWidget): # Put the following calls in Qt's event queue, otherwise # the UI won't update properly QtCore.QTimer.singleShot(0, self.stop_eip) - QtCore.QTimer.singleShot(0, partial(self.set_eip_status, + QtCore.QTimer.singleShot(0, partial(self.set_global_status, self.tr("Unable to start VPN, " "it's already " "running."))) diff --git a/src/leap/gui/ui/statuspanel.ui b/src/leap/gui/ui/statuspanel.ui index 67f5f669..1a2c77ad 100644 --- a/src/leap/gui/ui/statuspanel.ui +++ b/src/leap/gui/ui/statuspanel.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>506</width> - <height>403</height> + <width>542</width> + <height>477</height> </rect> </property> <property name="windowTitle"> @@ -29,200 +29,193 @@ </item> <item> <widget class="QWidget" name="status_rows" native="true"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="styleSheet"> <string notr="true"/> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="spacing"> - <number>12</number> - </property> - <property name="leftMargin"> - <number>16</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="eip_status_row"> - <property name="leftMargin"> - <number>0</number> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="eip_controls"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Encrypted Internet: </string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblEIPStatus"> + <property name="styleSheet"> + <string notr="true">font: bold;</string> + </property> + <property name="text"> + <string>Off</string> + </property> + <property name="textFormat"> + <enum>Qt::AutoText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnEipStartStop"> + <property name="text"> + <string>Turn On</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>11</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0" rowspan="2"> + <widget class="QLabel" name="lblVPNStatusIcon"> + <property name="maximumSize"> + <size> + <width>64</width> + <height>64</height> + </size> </property> - <property name="topMargin"> - <number>0</number> + <property name="text"> + <string/> </property> + <property name="pixmap"> + <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/64/network-eip-down.png</pixmap> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="eip_bandwidth"> + <property name="spacing"> + <number>4</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblUpload"> + <property name="text"> + <string>0.0 Kb</string> + </property> + </widget> + </item> <item> - <widget class="QLabel" name="lblVPNStatusIcon"> - <property name="maximumSize"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> <size> - <width>64</width> - <height>64</height> + <width>20</width> + <height>20</height> </size> </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_7"> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/64/network-eip-down.png</pixmap> + <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap> </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + </widget> + </item> + <item> + <widget class="QLabel" name="lblDownload"> + <property name="text"> + <string>0.0 Kb</string> </property> </widget> </item> <item> - <layout class="QVBoxLayout" name="eip_split_row"> - <property name="spacing"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="eip_controls"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Encrypted Internet: </string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lblEIPStatus"> - <property name="styleSheet"> - <string notr="true">font: bold;</string> - </property> - <property name="text"> - <string>Off</string> - </property> - <property name="textFormat"> - <enum>Qt::AutoText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="btnEipStartStop"> - <property name="text"> - <string>Turn On</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="eip_bandwidth"> - <property name="spacing"> - <number>4</number> - </property> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lblUpload"> - <property name="text"> - <string>0.0 Kb</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap resource="../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lblDownload"> - <property name="text"> - <string>0.0 Kb</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>0</width> - <height>11</height> - </size> - </property> - </spacer> - </item> - </layout> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> </item> </layout> </item> + <item row="3" column="0" colspan="2"> + <widget class="QGroupBox" name="globalStatusBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="lblGlobalStatus"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> </layout> </widget> </item> @@ -240,6 +233,9 @@ </spacer> </item> </layout> + <zorder>lblProvider</zorder> + <zorder>status_rows</zorder> + <zorder>globalStatusBox</zorder> </widget> <resources> <include location="../../../../data/resources/icons.qrc"/> diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py index 7449acd0..56df0b1c 100644 --- a/src/leap/services/eip/vpnlaunchers.py +++ b/src/leap/services/eip/vpnlaunchers.py @@ -216,7 +216,7 @@ def _try_to_launch_agent(): Tries to launch a polkit daemon. """ opts = [ - "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1&", + "/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1", # XXX add kde thing here ] for cmd in opts: diff --git a/src/leap/services/eip/vpnprocess.py b/src/leap/services/eip/vpnprocess.py index d9fa85a6..0ec56ae7 100644 --- a/src/leap/services/eip/vpnprocess.py +++ b/src/leap/services/eip/vpnprocess.py @@ -142,6 +142,14 @@ class VPN(object): # after running out of patience, we try a killProcess logger.debug("Process did not died. Sending a SIGKILL.") + self.killit() + + def killit(self): + """ + Sends a kill signal to the process. + """ + self._stop_pollers() + self._vpnproc.aborted = True self._vpnproc.killProcess() def terminate(self, shutdown=False): @@ -225,11 +233,20 @@ class VPNManager(object): self._reactor = reactor self._tn = None self._qtsigs = qtsigs + self._aborted = False @property def qtsigs(self): return self._qtsigs + @property + def aborted(self): + return self._aborted + + @aborted.setter + def aborted(self, value): + self._aborted = value + def _seek_to_eof(self): """ Read as much as available. Position seek pointer to end of stream @@ -378,7 +395,7 @@ class VPNManager(object): """ # TODO decide about putting a max_lim to retries and signaling # an error. - if not self.is_connected(): + if not self.aborted and not self.is_connected(): self.connect_to_management(self._socket_host, self._socket_port) self._reactor.callLater( self.CONNECTION_RETRY_TIME, @@ -611,6 +628,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): self._last_state = None self._last_status = None + self._alive = False # processProtocol methods @@ -620,6 +638,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): .. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa """ + self._alive = True + self.aborted = False self.try_to_connect_to_management() def outReceived(self, data): @@ -643,6 +663,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): exit_code = reason.value.exitCode if isinstance(exit_code, int): logger.debug("processExited, status %d" % (exit_code,)) + self.qtsigs.process_finished.emit(exit_code) + self._alive = False def processEnded(self, reason): """ @@ -661,13 +683,15 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager): """ Polls connection status. """ - self.get_status() + if self._alive: + self.get_status() def pollState(self): """ Polls connection state. """ - self.get_state() + if self._alive: + self.get_state() # launcher |