summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2013-06-24 11:42:56 -0300
committerTomás Touceda <chiiph@leap.se>2013-06-24 11:42:56 -0300
commita628dcbc372161d979548c09a3cb22f6878c8bd1 (patch)
tree1bf7d292dd7b0b76c2825ae8cd504f717da1e16b /src
parent071cbe0e31f73ad774551a5d5474be9edb7a9c5c (diff)
parent19c90e02a65d1d6fe30e6915cd2a9440878aef83 (diff)
Merge remote-tracking branch 'kali/feature/better-vpn-control' into develop
Diffstat (limited to 'src')
-rw-r--r--src/leap/gui/mainwindow.py85
-rw-r--r--src/leap/gui/statuspanel.py46
-rw-r--r--src/leap/gui/ui/statuspanel.ui346
-rw-r--r--src/leap/services/eip/vpnlaunchers.py2
-rw-r--r--src/leap/services/eip/vpnprocess.py30
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