summaryrefslogtreecommitdiff
path: root/src/leap
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap')
-rw-r--r--src/leap/app.py8
-rw-r--r--src/leap/gui/login.py6
-rw-r--r--src/leap/gui/mainwindow.py157
-rw-r--r--src/leap/services/eip/vpnlaunchers.py26
-rw-r--r--src/leap/services/eip/vpnprocess.py27
-rw-r--r--src/leap/services/mail/imap.py42
-rw-r--r--src/leap/services/soledad/soledadbootstrapper.py22
7 files changed, 204 insertions, 84 deletions
diff --git a/src/leap/app.py b/src/leap/app.py
index 6ba27813..e7a8aa42 100644
--- a/src/leap/app.py
+++ b/src/leap/app.py
@@ -142,6 +142,7 @@ def main():
bypass_checks = getattr(opts, 'danger', False)
debug = opts.debug
logfile = opts.log_file
+ openvpn_verb = opts.openvpn_verb
logger = add_logger_handlers(debug, logfile)
replace_stdout_stderr_with_logging(logger)
@@ -202,6 +203,7 @@ def main():
window = MainWindow(
lambda: twisted_main.quit(app),
standalone=standalone,
+ openvpn_verb=openvpn_verb,
bypass_checks=bypass_checks)
sigint_window = partial(sigint_handler, window, logger=logger)
@@ -210,8 +212,10 @@ def main():
if IS_MAC:
window.raise_()
- tx_app = leap_services()
- assert(tx_app)
+ # This was a good idea, but for this to work as intended we
+ # should centralize the start of all services in there.
+ #tx_app = leap_services()
+ #assert(tx_app)
# Run main loop
twisted_main.start(app)
diff --git a/src/leap/gui/login.py b/src/leap/gui/login.py
index 3c994597..de0b2d50 100644
--- a/src/leap/gui/login.py
+++ b/src/leap/gui/login.py
@@ -197,18 +197,18 @@ class LoginWidget(QtGui.QWidget):
"""
self.ui.lnUser.setEnabled(enabled)
self.ui.lnPassword.setEnabled(enabled)
- self.ui.btnLogin.setEnabled(enabled)
self.ui.chkRemember.setEnabled(enabled)
self.ui.cmbProviders.setEnabled(enabled)
- def set_cancel(self, enabled=False):
+ self._set_cancel(not enabled)
+
+ def _set_cancel(self, enabled=False):
"""
Enables or disables the cancel action in the "log in" process.
:param enabled: wether it should be enabled or not
:type enabled: bool
"""
- self.ui.btnLogin.setEnabled(enabled)
text = self.tr("Cancel")
login_or_cancel = self.cancel_login
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py
index a1ba4df4..5c7a3928 100644
--- a/src/leap/gui/mainwindow.py
+++ b/src/leap/gui/mainwindow.py
@@ -45,6 +45,7 @@ from leap.services.eip.providerbootstrapper import ProviderBootstrapper
# XXX: Soledad might not work out of the box in Windows, issue #2932
from leap.services.soledad.soledadbootstrapper import SoledadBootstrapper
from leap.services.mail.smtpbootstrapper import SMTPBootstrapper
+from leap.services.mail import imap
from leap.platform_init import IS_WIN, IS_MAC
from leap.platform_init.initializers import init_platform
@@ -94,12 +95,15 @@ class MainWindow(QtGui.QMainWindow):
# Signals
new_updates = QtCore.Signal(object)
raise_window = QtCore.Signal([])
+ soledad_ready = QtCore.Signal([])
# We use this flag to detect abnormal terminations
user_stopped_eip = False
def __init__(self, quit_callback,
- standalone=False, bypass_checks=False):
+ standalone=False,
+ openvpn_verb=1,
+ bypass_checks=False):
"""
Constructor for the client main window
@@ -140,6 +144,9 @@ class MainWindow(QtGui.QMainWindow):
self.ui.stackedWidget.widget(self.LOGIN_INDEX))
self.ui.loginLayout.addWidget(self._login_widget)
+ # Signals
+ # TODO separate logic from ui signals.
+
self._login_widget.login.connect(self._login)
self._login_widget.cancel_login.connect(self._cancel_login)
self._login_widget.show_wizard.connect(
@@ -210,7 +217,7 @@ class MainWindow(QtGui.QMainWindow):
self._smtp_bootstrapper.download_config.connect(
self._smtp_bootstrapped_stage)
- self._vpn = VPN()
+ self._vpn = VPN(openvpn_verb=openvpn_verb)
self._vpn.qtsigs.state_changed.connect(
self._status_panel.update_vpn_state)
self._vpn.qtsigs.status_changed.connect(
@@ -260,7 +267,9 @@ class MainWindow(QtGui.QMainWindow):
self.ui.lblNewUpdates.setVisible(False)
self.ui.btnMore.setVisible(False)
self.ui.btnMore.clicked.connect(self._updates_details)
+
self.new_updates.connect(self._react_to_new_updates)
+ self.soledad_ready.connect(self._start_imap_service)
init_platform()
@@ -273,6 +282,7 @@ class MainWindow(QtGui.QMainWindow):
self._soledad = None
self._keymanager = None
+ self._imap_service = None
self._login_defer = None
self._download_provider_defer = None
@@ -804,7 +814,6 @@ class MainWindow(QtGui.QMainWindow):
self._login_widget.set_status(self.tr("Logging in..."), error=False)
self._login_widget.set_enabled(False)
- self._login_widget.set_cancel(True)
if self._login_widget.get_remember() and has_keyring():
# in the keyring and in the settings
@@ -832,7 +841,6 @@ class MainWindow(QtGui.QMainWindow):
Stops the login sequence.
"""
logger.debug("Cancelling log in.")
- self._login_widget.set_cancel(False)
if self._download_provider_defer:
logger.debug("Cancelling download provider defer.")
@@ -951,29 +959,41 @@ class MainWindow(QtGui.QMainWindow):
passed = data[self._soledad_bootstrapper.PASSED_KEY]
if not passed:
logger.error(data[self._soledad_bootstrapper.ERROR_KEY])
- else:
- logger.debug("Done bootstrapping Soledad")
+ return
- self._soledad = self._soledad_bootstrapper.soledad
- self._keymanager = self._soledad_bootstrapper.keymanager
+ logger.debug("Done bootstrapping Soledad")
- if self._provider_config.provides_mx() and \
- self._enabled_services.count(self.MX_SERVICE) > 0:
- self._smtp_bootstrapper.run_smtp_setup_checks(
- self._provider_config,
- self._smtp_config,
- True)
+ self._soledad = self._soledad_bootstrapper.soledad
+ self._keymanager = self._soledad_bootstrapper.keymanager
+
+ # Ok, now soledad is ready, so we can allow other things that
+ # depend on soledad to start.
+
+ # this will trigger start_imap_service
+ self.soledad_ready.emit()
+
+ # TODO connect all these activations to the soledad_ready
+ # signal so the logic is clearer to follow.
+
+ if self._provider_config.provides_mx() and \
+ self._enabled_services.count(self.MX_SERVICE) > 0:
+ self._smtp_bootstrapper.run_smtp_setup_checks(
+ self._provider_config,
+ self._smtp_config,
+ True)
+ else:
+ if self._enabled_services.count(self.MX_SERVICE) > 0:
+ pass # TODO: show MX status
+ #self._status_panel.set_eip_status(
+ # self.tr("%s does not support MX") %
+ # (self._provider_config.get_domain(),),
+ # error=True)
else:
- if self._enabled_services.count(self.MX_SERVICE) > 0:
- pass # TODO: show MX status
- #self._status_panel.set_eip_status(
- # self.tr("%s does not support MX") %
- # (self._provider_config.get_domain(),),
- # error=True)
- else:
- pass # TODO: show MX status
- #self._status_panel.set_eip_status(
- # self.tr("MX is disabled"))
+ pass # TODO: show MX status
+ #self._status_panel.set_eip_status(
+ # self.tr("MX is disabled"))
+
+ # Service control methods: smtp
def _smtp_bootstrapped_stage(self, data):
"""
@@ -991,29 +1011,41 @@ class MainWindow(QtGui.QMainWindow):
passed = data[self._smtp_bootstrapper.PASSED_KEY]
if not passed:
logger.error(data[self._smtp_bootstrapper.ERROR_KEY])
- else:
- logger.debug("Done bootstrapping SMTP")
-
- hosts = self._smtp_config.get_hosts()
- # TODO: handle more than one host and define how to choose
- if len(hosts) > 0:
- hostname = hosts.keys()[0]
- logger.debug("Using hostname %s for SMTP" % (hostname,))
- host = hosts[hostname][self.IP_KEY].encode("utf-8")
- port = hosts[hostname][self.PORT_KEY]
- # TODO: pick local smtp port in a better way
- # TODO: Make the encrypted_only configurable
-
- from leap.mail.smtp import setup_smtp_relay
- client_cert = self._eip_config.get_client_cert_path(
- self._provider_config)
- setup_smtp_relay(port=1234,
- keymanager=self._keymanager,
- smtp_host=host,
- smtp_port=port,
- smtp_cert=client_cert,
- smtp_key=client_cert,
- encrypted_only=False)
+ return
+ logger.debug("Done bootstrapping SMTP")
+
+ hosts = self._smtp_config.get_hosts()
+ # TODO: handle more than one host and define how to choose
+ if len(hosts) > 0:
+ hostname = hosts.keys()[0]
+ logger.debug("Using hostname %s for SMTP" % (hostname,))
+ host = hosts[hostname][self.IP_KEY].encode("utf-8")
+ port = hosts[hostname][self.PORT_KEY]
+ # TODO: pick local smtp port in a better way
+ # TODO: Make the encrypted_only configurable
+
+ from leap.mail.smtp import setup_smtp_relay
+ client_cert = self._eip_config.get_client_cert_path(
+ self._provider_config)
+ setup_smtp_relay(port=1234,
+ keymanager=self._keymanager,
+ smtp_host=host,
+ smtp_port=port,
+ smtp_cert=client_cert,
+ smtp_key=client_cert,
+ encrypted_only=False)
+
+ def _start_imap_service(self):
+ """
+ SLOT
+ TRIGGERS:
+ soledad_ready
+ """
+ logger.debug('Starting imap service')
+
+ self._imap_service = imap.start_imap_service(
+ self._soledad,
+ self._keymanager)
def _get_socket_host(self):
"""
@@ -1068,6 +1100,7 @@ class MainWindow(QtGui.QMainWindow):
self._status_panel.eip_started()
+ # XXX refactor into status_panel method?
self._action_eip_startstop.setText(self.tr("Turn OFF"))
self._action_eip_startstop.disconnect(self)
self._action_eip_startstop.triggered.connect(
@@ -1301,7 +1334,6 @@ class MainWindow(QtGui.QMainWindow):
"""
passed = data[self._provider_bootstrapper.PASSED_KEY]
if not passed:
- self._login_widget.set_cancel(False)
self._login_widget.set_enabled(True)
self._login_widget.set_status(
self.tr("Unable to connect: Problem with provider"))
@@ -1409,6 +1441,9 @@ class MainWindow(QtGui.QMainWindow):
"""
logger.debug('About to quit, doing cleanup...')
+ if self._imap_service is not None:
+ self._imap_service.stop()
+
if self._srp_auth is not None:
if self._srp_auth.get_session_id() is not None or \
self._srp_auth.get_token() is not None:
@@ -1421,16 +1456,28 @@ class MainWindow(QtGui.QMainWindow):
else:
logger.error("No instance of soledad was found.")
- logger.debug('Cleaning pidfiles')
- self._cleanup_pidfiles()
-
logger.debug('Terminating vpn')
self._vpn.terminate(shutdown=True)
+ if self._login_defer:
+ logger.debug("Cancelling login defer.")
+ self._login_defer.cancel()
+
+ if self._download_provider_defer:
+ logger.debug("Cancelling download provider defer.")
+ self._download_provider_defer.cancel()
+
+ # TODO missing any more cancels?
+
+ logger.debug('Cleaning pidfiles')
+ self._cleanup_pidfiles()
+
def quit(self):
"""
Cleanup and tidely close the main window before quitting.
"""
+ # TODO: separate the shutting down of services from the
+ # UI stuff.
self._cleanup_and_quit()
self._really_quit = True
@@ -1441,14 +1488,6 @@ class MainWindow(QtGui.QMainWindow):
if self._logger_window:
self._logger_window.close()
- if self._login_defer:
- logger.debug("Cancelling login defer.")
- self._login_defer.cancel()
-
- if self._download_provider_defer:
- logger.debug("Cancelling download provider defer.")
- self._download_provider_defer.cancel()
-
self.close()
if self._quit_callback:
diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py
index 526f1ba4..dadbf859 100644
--- a/src/leap/services/eip/vpnlaunchers.py
+++ b/src/leap/services/eip/vpnlaunchers.py
@@ -352,7 +352,7 @@ class LinuxVPNLauncher(VPNLauncher):
return None
def get_vpn_command(self, eipconfig=None, providerconfig=None,
- socket_host=None, socket_port="unix"):
+ socket_host=None, socket_port="unix", openvpn_verb=1):
"""
Returns the platform dependant vpn launching command. It will
look for openvpn in the regular paths and algo in
@@ -375,6 +375,9 @@ class LinuxVPNLauncher(VPNLauncher):
socket, or port otherwise
:type socket_port: str
+ :param openvpn_verb: openvpn verbosity wanted
+ :type openvpn_verb: int
+
:return: A VPN command ready to be launched
:rtype: list
"""
@@ -404,7 +407,7 @@ class LinuxVPNLauncher(VPNLauncher):
args.append(openvpn)
openvpn = first(pkexec)
- # TODO: handle verbosity
+ args += ['--verb', '%d' % (openvpn_verb,)]
gateway_selector = VPNGatewaySelector(eipconfig)
gateways = gateway_selector.get_gateways()
@@ -604,7 +607,7 @@ class DarwinVPNLauncher(VPNLauncher):
return self.COCOASUDO, args
def get_vpn_command(self, eipconfig=None, providerconfig=None,
- socket_host=None, socket_port="unix"):
+ socket_host=None, socket_port="unix", openvpn_verb=1):
"""
Returns the platform dependant vpn launching command
@@ -623,6 +626,9 @@ class DarwinVPNLauncher(VPNLauncher):
socket, or port otherwise
:type socket_port: str
+ :param openvpn_verb: openvpn verbosity wanted
+ :type openvpn_verb: int
+
:return: A VPN command ready to be launched
:rtype: list
"""
@@ -651,7 +657,7 @@ class DarwinVPNLauncher(VPNLauncher):
openvpn = first(openvpn_possibilities)
args = [openvpn]
- # TODO: handle verbosity
+ args += ['--verb', '%d' % (openvpn_verb,)]
gateway_selector = VPNGatewaySelector(eipconfig)
gateways = gateway_selector.get_gateways()
@@ -768,9 +774,10 @@ class WindowsVPNLauncher(VPNLauncher):
OPENVPN_BIN = 'openvpn_leap.exe'
# XXX UPDOWN_FILES ... we do not have updown files defined yet!
+ # (and maybe we won't)
def get_vpn_command(self, eipconfig=None, providerconfig=None,
- socket_host=None, socket_port="9876"):
+ socket_host=None, socket_port="9876", openvpn_verb=1):
"""
Returns the platform dependant vpn launching command. It will
look for openvpn in the regular paths and algo in
@@ -780,14 +787,20 @@ class WindowsVPNLauncher(VPNLauncher):
: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
+ :param openvpn_verb: the openvpn verbosity wanted
+ :type openvpn_verb: int
+
:return: A VPN command ready to be launched
:rtype: list
"""
@@ -810,8 +823,7 @@ class WindowsVPNLauncher(VPNLauncher):
openvpn = first(openvpn_possibilities)
args = []
-
- # TODO: handle verbosity
+ args += ['--verb', '%d' % (openvpn_verb,)]
gateway_selector = VPNGatewaySelector(eipconfig)
gateways = gateway_selector.get_gateways()
diff --git a/src/leap/services/eip/vpnprocess.py b/src/leap/services/eip/vpnprocess.py
index c4bdb30c..5b07a3cf 100644
--- a/src/leap/services/eip/vpnprocess.py
+++ b/src/leap/services/eip/vpnprocess.py
@@ -80,7 +80,9 @@ class VPN(object):
TERMINATE_MAXTRIES = 10
TERMINATE_WAIT = 1 # secs
- def __init__(self):
+ OPENVPN_VERB = "openvpn_verb"
+
+ def __init__(self, **kwargs):
"""
Instantiate empty attributes and get a copy
of a QObject containing the QSignals that we will pass along
@@ -92,6 +94,8 @@ class VPN(object):
self._reactor = reactor
self._qtsigs = VPNSignals()
+ self._openvpn_verb = kwargs.get(self.OPENVPN_VERB, None)
+
@property
def qtsigs(self):
return self._qtsigs
@@ -108,9 +112,12 @@ class VPN(object):
"""
self._stop_pollers()
kwargs['qtsigs'] = self.qtsigs
+ kwargs['openvpn_verb'] = self._openvpn_verb
# start the main vpn subprocess
vpnproc = VPNProcess(*args, **kwargs)
+ #qtsigs=self.qtsigs,
+ #openvpn_verb=self._openvpn_verb)
if vpnproc.get_openvpn_process():
logger.info("Another vpn process is running. Will try to stop it.")
@@ -566,7 +573,12 @@ class VPNManager(object):
# we should check that cmdline BEGINS
# with openvpn or with our wrapper
# (pkexec / osascript / whatever)
- if "openvpn" in ' '.join(p.cmdline):
+
+ # This needs more work, see #3268, but for the moment
+ # we need to be able to filter out arguments in the form
+ # --openvpn-foo, since otherwise we are shooting ourselves
+ # in the feet.
+ if any(map(lambda s: s.startswith("openvpn"), p.cmdline)):
openvpn_process = p
break
except psutil.error.AccessDenied:
@@ -645,7 +657,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
"""
def __init__(self, eipconfig, providerconfig, socket_host, socket_port,
- qtsigs):
+ qtsigs, openvpn_verb):
"""
:param eipconfig: eip configuration object
:type eipconfig: EIPConfig
@@ -663,6 +675,10 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
:param qtsigs: a QObject containing the Qt signals used to notify the
UI.
:type qtsigs: QObject
+
+ :param openvpn_verb: the desired level of verbosity in the
+ openvpn invocation
+ :type openvpn_verb: int
"""
VPNManager.__init__(self, qtsigs=qtsigs)
leap_assert_type(eipconfig, EIPConfig)
@@ -682,6 +698,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
self._last_status = None
self._alive = False
+ self._openvpn_verb = openvpn_verb
+
# processProtocol methods
def connectionMade(self):
@@ -757,7 +775,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
eipconfig=self._eipconfig,
providerconfig=self._providerconfig,
socket_host=self._socket_host,
- socket_port=self._socket_port)
+ socket_port=self._socket_port,
+ openvpn_verb=self._openvpn_verb)
return map(str, cmd)
# shutdown
diff --git a/src/leap/services/mail/imap.py b/src/leap/services/mail/imap.py
new file mode 100644
index 00000000..4dceb2ad
--- /dev/null
+++ b/src/leap/services/mail/imap.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# imap.py
+# Copyright (C) 2013 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+Initialization of imap service
+"""
+import logging
+import sys
+
+from leap.mail.imap.service import imap
+from twisted.python import log
+
+logger = logging.getLogger(__name__)
+
+
+def start_imap_service(*args, **kwargs):
+ """
+ Initializes and run imap service.
+
+ :returns: twisted.internet.task.LoopingCall instance
+ """
+ logger.debug('Launching imap service')
+
+ # Uncomment the next two lines to get a separate debugging log
+ # TODO handle this by a separate flag.
+ #log.startLogging(open('/tmp/leap-imap.log', 'w'))
+ #log.startLogging(sys.stdout)
+
+ return imap.run_service(*args, **kwargs)
diff --git a/src/leap/services/soledad/soledadbootstrapper.py b/src/leap/services/soledad/soledadbootstrapper.py
index 422352ea..7ac4203b 100644
--- a/src/leap/services/soledad/soledadbootstrapper.py
+++ b/src/leap/services/soledad/soledadbootstrapper.py
@@ -23,6 +23,7 @@ import logging
import os
from PySide import QtCore
+from u1db import errors as u1db_errors
from leap.common.check import leap_assert, leap_assert_type
from leap.common.files import get_mtime
@@ -103,15 +104,18 @@ class SoledadBootstrapper(AbstractBootstrapper):
# TODO: If selected server fails, retry with another host
# (issue #3309)
- self._soledad = Soledad(uuid,
- self._password.encode("utf-8"),
- secrets_path=secrets_path,
- local_db_path=local_db_path,
- server_url=server_url,
- cert_file=cert_file,
- auth_token=srp_auth.get_token())
-
- self._soledad.sync()
+ try:
+ self._soledad = Soledad(
+ uuid,
+ self._password.encode("utf-8"),
+ secrets_path=secrets_path,
+ local_db_path=local_db_path,
+ server_url=server_url,
+ cert_file=cert_file,
+ auth_token=srp_auth.get_token())
+ self._soledad.sync()
+ except u1db_errors.Unauthorized:
+ logger.error("Error while initializing soledad.")
else:
raise Exception("No soledad server found")