summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug_systray_behavior2
-rw-r--r--changes/feature_windows1
-rw-r--r--src/leap/app.py4
-rw-r--r--src/leap/config/prefixers.py22
-rw-r--r--src/leap/gui/mainwindow.py46
-rw-r--r--src/leap/services/eip/vpnlaunchers.py108
-rw-r--r--src/leap/util/request_helpers.py5
7 files changed, 168 insertions, 20 deletions
diff --git a/changes/bug_systray_behavior b/changes/bug_systray_behavior
new file mode 100644
index 00000000..28b4caa0
--- /dev/null
+++ b/changes/bug_systray_behavior
@@ -0,0 +1,2 @@
+ o Do not hide the application if the user right clicked the system
+ tray icon. \ No newline at end of file
diff --git a/changes/feature_windows b/changes/feature_windows
new file mode 100644
index 00000000..f302173b
--- /dev/null
+++ b/changes/feature_windows
@@ -0,0 +1 @@
+ o Add Windows support. \ No newline at end of file
diff --git a/src/leap/app.py b/src/leap/app.py
index 14d3c69c..7cf78dc9 100644
--- a/src/leap/app.py
+++ b/src/leap/app.py
@@ -27,6 +27,10 @@ from leap.util import leap_argparse
from leap.gui import locale_rc
from leap.gui.mainwindow import MainWindow
+import codecs
+codecs.register(lambda name: codecs.lookup('utf-8')
+ if name == 'cp65001' else None)
+
def sigint_handler(*args, **kwargs):
logger = kwargs.get('logger', None)
diff --git a/src/leap/config/prefixers.py b/src/leap/config/prefixers.py
index 5a9b2112..460e5b46 100644
--- a/src/leap/config/prefixers.py
+++ b/src/leap/config/prefixers.py
@@ -99,6 +99,28 @@ class DarwinPrefixer(Prefixer):
return os.getenv("LEAP_CLIENT_PATH", config_dir)
+class WindowsPrefixer(Prefixer):
+ """
+ Config prefixer for the Windows platform
+ """
+
+ def get_path_prefix(self, standalone=False):
+ """
+ Returns the platform dependant path prefixer.
+ This method expects an env variable named LEAP_CLIENT_PATH if
+ standalone is used.
+
+ @param standalone: if True it will return the prefix for a
+ standalone application. Otherwise, it will return the system
+ default for configuration storage.
+ @type standalone: bool
+ """
+ config_dir = BaseDirectory.xdg_config_home
+
+ if not standalone:
+ return config_dir
+ return os.path.join(os.getcwd(), "config")
+
if __name__ == "__main__":
try:
abs_prefixer = Prefixer()
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py
index ca6f1a8b..863640ef 100644
--- a/src/leap/gui/mainwindow.py
+++ b/src/leap/gui/mainwindow.py
@@ -18,31 +18,33 @@
"""
Main window for the leap client
"""
-import os
import logging
+import os
+import platform
import tempfile
-import keyring
-
-from PySide import QtCore, QtGui
from functools import partial
-from ui_mainwindow import Ui_MainWindow
+import keyring
+from PySide import QtCore, QtGui
from leap.common.check import leap_assert
from leap.config.leapsettings import LeapSettings
from leap.config.providerconfig import ProviderConfig
from leap.crypto.srpauth import SRPAuth
+from leap.gui.wizard import Wizard
+from leap.services.eip.eipbootstrapper import EIPBootstrapper
+from leap.services.eip.eipconfig import EIPConfig
+from leap.services.eip.providerbootstrapper import ProviderBootstrapper
from leap.platform_init.initializers import init_platform
from leap.services.eip.vpn import VPN
from leap.services.eip.vpnlaunchers import (VPNLauncherException,
OpenVPNNotFoundException,
EIPNoPkexecAvailable,
EIPNoPolkitAuthAgentAvailable)
-from leap.services.eip.providerbootstrapper import ProviderBootstrapper
-from leap.services.eip.eipbootstrapper import EIPBootstrapper
-from leap.services.eip.eipconfig import EIPConfig
-from leap.gui.wizard import Wizard
-from leap.util.checkerthread import CheckerThread
from leap.util import __version__ as VERSION
+from leap.util.checkerthread import CheckerThread
+
+from ui_mainwindow import Ui_MainWindow
+
logger = logging.getLogger(__name__)
@@ -291,18 +293,19 @@ class MainWindow(QtGui.QMainWindow):
self._vpn_systray.setIcon(QtGui.QIcon(self.ERROR_ICON))
self._vpn_systray.setVisible(False)
- def _toggle_visible(self):
+ def _toggle_visible(self, reason=None):
"""
SLOT
TRIGGER: self._systray.activated
Toggles the window visibility
"""
- self.setVisible(not self.isVisible())
- action_visible_text = self.tr("Hide")
- if not self.isVisible():
- action_visible_text = self.tr("Show")
- self._action_visible.setText(action_visible_text)
+ if reason != QtGui.QSystemTrayIcon.Context:
+ self.setVisible(not self.isVisible())
+ action_visible_text = self.tr("Hide")
+ if not self.isVisible():
+ action_visible_text = self.tr("Show")
+ self._action_visible.setText(action_visible_text)
def _center_window(self):
"""
@@ -609,9 +612,14 @@ class MainWindow(QtGui.QMainWindow):
"""
# TODO: make this properly multiplatform
- host = os.path.join(tempfile.mkdtemp(prefix="leap-tmp"),
- 'openvpn.socket')
- port = "unix"
+
+ if platform.system() == "Windows":
+ host = "localhost"
+ port = "9876"
+ else:
+ host = os.path.join(tempfile.mkdtemp(prefix="leap-tmp"),
+ 'openvpn.socket')
+ port = "unix"
return host, port
diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py
index 9761c225..57a8092e 100644
--- a/src/leap/services/eip/vpnlaunchers.py
+++ b/src/leap/services/eip/vpnlaunchers.py
@@ -275,6 +275,7 @@ class LinuxVPNLauncher(VPNLauncher):
providerconfig.get_path_prefix(),
"..", "lib")}
+
class DarwinVPNLauncher(VPNLauncher):
"""
VPN launcher for the Darwin Platform
@@ -391,6 +392,113 @@ class DarwinVPNLauncher(VPNLauncher):
return [command] + cmd_args
+class WindowsVPNLauncher(VPNLauncher):
+ """
+ VPN launcher for the Windows platform
+ """
+
+ OPENVPN_BIN = 'openvpn_leap.exe'
+
+ def get_vpn_command(self, eipconfig=None, providerconfig=None,
+ socket_host=None, socket_port="9876"):
+ """
+ Returns the platform dependant vpn launching command. It will
+ look for openvpn in the regular paths and algo in
+ path_prefix/apps/eip/ (in case standalone is set)
+
+ Might raise VPNException.
+
+ @param eipconfig: eip configuration object
+ @type eipconfig: EIPConfig
+ @param providerconfig: provider specific configuration
+ @type providerconfig: ProviderConfig
+ @param socket_host: either socket path (unix) or socket IP
+ @type socket_host: str
+ @param socket_port: either string "unix" if it's a unix
+ socket, or port otherwise
+ @type socket_port: str
+
+ @return: A VPN command ready to be launched
+ @rtype: list
+ """
+ leap_assert(eipconfig, "We need an eip config")
+ leap_assert_type(eipconfig, EIPConfig)
+ leap_assert(providerconfig, "We need a provider config")
+ leap_assert_type(providerconfig, ProviderConfig)
+ leap_assert(socket_host, "We need a socket host!")
+ leap_assert(socket_port, "We need a socket port!")
+ leap_assert(socket_port != "unix",
+ "We cannot use unix sockets in windows!")
+
+ openvpn_possibilities = which(
+ self.OPENVPN_BIN,
+ path_extension=os.path.join(providerconfig.get_path_prefix(),
+ "..", "apps", "eip"))
+
+ if len(openvpn_possibilities) == 0:
+ raise OpenVPNNotFoundException()
+
+ openvpn = openvpn_possibilities[0]
+ args = []
+
+ # TODO: handle verbosity
+
+ gateway_ip = str(eipconfig.get_gateway_ip(0))
+
+ logger.debug("Using gateway ip %s" % (gateway_ip,))
+
+ args += [
+ '--client',
+ '--dev', 'tun',
+ '--persist-tun',
+ '--persist-key',
+ '--remote', gateway_ip, '1194', 'udp',
+ '--tls-client',
+ '--remote-cert-tls',
+ 'server'
+ ]
+
+ openvpn_configuration = eipconfig.get_openvpn_configuration()
+ # XXX sanitize this
+ for key, value in openvpn_configuration.items():
+ args += ['--%s' % (key,), value]
+
+ args += [
+ '--user', getpass.getuser(),
+ #'--group', grp.getgrgid(os.getgroups()[-1]).gr_name
+ ]
+
+ args += [
+ '--management-signal',
+ '--management', socket_host, socket_port,
+ '--script-security', '2'
+ ]
+
+ args += [
+ '--cert', eipconfig.get_client_cert_path(providerconfig),
+ '--key', eipconfig.get_client_cert_path(providerconfig),
+ '--ca', providerconfig.get_ca_cert_path()
+ ]
+
+ logger.debug("Running VPN with command:")
+ logger.debug("%s %s" % (openvpn, " ".join(args)))
+
+ return [openvpn] + args
+
+ def get_vpn_env(self, providerconfig):
+ """
+ Returns a dictionary with the custom env for the platform.
+ This is mainly used for setting LD_LIBRARY_PATH to the correct
+ path when distributing a standalone client
+
+ @param providerconfig: provider specific configuration
+ @type providerconfig: ProviderConfig
+
+ @rtype: dict
+ """
+ return {}
+
+
if __name__ == "__main__":
logger = logging.getLogger(name='leap')
logger.setLevel(logging.DEBUG)
diff --git a/src/leap/util/request_helpers.py b/src/leap/util/request_helpers.py
index c5d0f3f5..019ff353 100644
--- a/src/leap/util/request_helpers.py
+++ b/src/leap/util/request_helpers.py
@@ -19,6 +19,8 @@
Request helpers for backward compatible "parsing" of requests
"""
+import time
+
import json
from dateutil import parser as dateparser
@@ -50,6 +52,7 @@ def get_content(request):
mtime = None
last_modified = request.headers.get('last-modified', None)
if last_modified:
- mtime = int(dateparser.parse(last_modified).strftime("%s"))
+ dt = dateparser.parse(unicode(last_modified))
+ mtime = int(time.mktime(dt.timetuple()) + dt.microsecond / 1000000.0)
return contents, mtime