summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/services
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/bitmask/services')
-rw-r--r--src/leap/bitmask/services/__init__.py3
-rw-r--r--src/leap/bitmask/services/eip/darwinvpnlauncher.py65
-rw-r--r--src/leap/bitmask/services/eip/vpnlauncher.py8
-rw-r--r--src/leap/bitmask/services/eip/vpnprocess.py190
-rw-r--r--src/leap/bitmask/services/mail/conductor.py25
-rw-r--r--src/leap/bitmask/services/mail/imap.py30
-rw-r--r--src/leap/bitmask/services/mail/imapcontroller.py8
-rw-r--r--src/leap/bitmask/services/mail/plumber.py3
-rw-r--r--src/leap/bitmask/services/mail/smtpbootstrapper.py42
-rw-r--r--src/leap/bitmask/services/soledad/soledadbootstrapper.py5
10 files changed, 261 insertions, 118 deletions
diff --git a/src/leap/bitmask/services/__init__.py b/src/leap/bitmask/services/__init__.py
index 54426669..d86f8aa4 100644
--- a/src/leap/bitmask/services/__init__.py
+++ b/src/leap/bitmask/services/__init__.py
@@ -154,6 +154,9 @@ def download_service_config(provider_config, service_config,
# Not modified
service_path = ("leap", "providers", provider_config.get_domain(),
service_json)
+
+ service_config.__class__.standalone = flags.STANDALONE
+
if res.status_code == 304:
logger.debug(
"{0} definition has not been modified".format(
diff --git a/src/leap/bitmask/services/eip/darwinvpnlauncher.py b/src/leap/bitmask/services/eip/darwinvpnlauncher.py
index 17fc11c2..e697b118 100644
--- a/src/leap/bitmask/services/eip/darwinvpnlauncher.py
+++ b/src/leap/bitmask/services/eip/darwinvpnlauncher.py
@@ -20,6 +20,7 @@ Darwin VPN launcher implementation.
import commands
import getpass
import os
+import socket
import sys
from leap.bitmask.logs.utils import get_logger
@@ -34,17 +35,46 @@ class EIPNoTunKextLoaded(VPNLauncherException):
pass
+class DarwinHelperCommand(object):
+
+ SOCKET_ADDR = '/tmp/bitmask-helper.socket'
+
+ def __init__(self):
+ pass
+
+ def _connect(self):
+ self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ try:
+ self._sock.connect(self.SOCKET_ADDR)
+ except socket.error, msg:
+ raise RuntimeError(msg)
+
+ def send(self, cmd, args=''):
+ # TODO check cmd is in allowed list
+ self._connect()
+ sock = self._sock
+ data = ""
+
+ command = cmd + ' ' + args + '/CMD'
+
+ try:
+ sock.sendall(command)
+ while '\n' not in data:
+ data += sock.recv(32)
+ finally:
+ sock.close()
+
+ return data
+
+
class DarwinVPNLauncher(VPNLauncher):
"""
VPN launcher for the Darwin Platform
"""
- COCOASUDO = "cocoasudo"
- # XXX need the good old magic translate for these strings
- # (look for magic in 0.2.0 release)
- SUDO_MSG = ("Bitmask needs administrative privileges to run "
- "Encrypted Internet.")
- INSTALL_MSG = ("\"Bitmask needs administrative privileges to install "
- "missing scripts and fix permissions.\"")
+ UP_SCRIPT = None
+ DOWN_SCRIPT = None
+
+ # TODO -- move this to bitmask-helper
# Hardcode the installation path for OSX for security, openvpn is
# run as root
@@ -56,14 +86,9 @@ class DarwinVPNLauncher(VPNLauncher):
INSTALL_PATH_ESCAPED,)
OPENVPN_BIN_PATH = "%s/Contents/Resources/%s" % (INSTALL_PATH,
OPENVPN_BIN)
-
- UP_SCRIPT = "%s/client.up.sh" % (OPENVPN_PATH,)
- DOWN_SCRIPT = "%s/client.down.sh" % (OPENVPN_PATH,)
- OPENVPN_DOWN_PLUGIN = '%s/openvpn-down-root.so' % (OPENVPN_PATH,)
-
- UPDOWN_FILES = (UP_SCRIPT, DOWN_SCRIPT, OPENVPN_DOWN_PLUGIN)
OTHER_FILES = []
+ # TODO deprecate ------------------------------------------------
@classmethod
def cmd_for_missing_scripts(kls, frompath):
"""
@@ -87,7 +112,11 @@ class DarwinVPNLauncher(VPNLauncher):
:returns: True if kext is loaded, False otherwise.
:rtype: bool
"""
- return bool(commands.getoutput('kextstat | grep "leap.tun"'))
+ loaded = bool(commands.getoutput(
+ 'kextstat | grep "net.sf.tuntaposx.tun"'))
+ if not loaded:
+ logger.error("tuntaposx extension not loaded!")
+ return loaded
@classmethod
def _get_icon_path(kls):
@@ -101,6 +130,7 @@ class DarwinVPNLauncher(VPNLauncher):
return os.path.join(resources_path, "bitmask.tiff")
+ # TODO deprecate ---------------------------------------------------------
@classmethod
def get_cocoasudo_ovpn_cmd(kls):
"""
@@ -120,6 +150,7 @@ class DarwinVPNLauncher(VPNLauncher):
return kls.COCOASUDO, args
+ # TODO deprecate ---------------------------------------------------------
@classmethod
def get_cocoasudo_installmissing_cmd(kls):
"""
@@ -171,12 +202,6 @@ class DarwinVPNLauncher(VPNLauncher):
# we use `super` in order to send the class to use
command = super(DarwinVPNLauncher, kls).get_vpn_command(
eipconfig, providerconfig, socket_host, socket_port, openvpn_verb)
-
- cocoa, cargs = kls.get_cocoasudo_ovpn_cmd()
- cargs.extend(command)
- command = cargs
- command.insert(0, cocoa)
-
command.extend(['--setenv', "LEAPUSER", getpass.getuser()])
return command
diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py
index c48f857c..16dfd9cf 100644
--- a/src/leap/bitmask/services/eip/vpnlauncher.py
+++ b/src/leap/bitmask/services/eip/vpnlauncher.py
@@ -29,7 +29,7 @@ from leap.bitmask.config import flags
from leap.bitmask.logs.utils import get_logger
from leap.bitmask.backend.settings import Settings, GATEWAY_AUTOMATIC
from leap.bitmask.config.providerconfig import ProviderConfig
-from leap.bitmask.platform_init import IS_LINUX
+from leap.bitmask.platform_init import IS_LINUX, IS_MAC
from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector
from leap.bitmask.util import force_eval
from leap.common.check import leap_assert, leap_assert_type
@@ -286,8 +286,8 @@ class VPNLauncher(object):
:rtype: list
"""
# FIXME
- # XXX remove method when we ditch UPDOWN in osx and win too
- if IS_LINUX:
+ # XXX remove method when we ditch UPDOWN in win too
+ if IS_LINUX or IS_MAC:
return []
else:
leap_assert(kls.UPDOWN_FILES is not None,
@@ -308,7 +308,7 @@ class VPNLauncher(object):
"""
leap_assert(kls.OTHER_FILES is not None,
"Need to define OTHER_FILES for this particular "
- "auncher before calling this method")
+ "launcher before calling this method")
other = force_eval(kls.OTHER_FILES)
file_exist = partial(_has_other_files, warn=False)
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index 586b50f5..580bd572 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -41,6 +41,7 @@ from leap.bitmask.config.providerconfig import ProviderConfig
from leap.bitmask.logs.utils import get_logger
from leap.bitmask.services.eip import get_vpn_launcher
from leap.bitmask.services.eip import linuxvpnlauncher
+from leap.bitmask.services.eip import darwinvpnlauncher
from leap.bitmask.services.eip.eipconfig import EIPConfig
from leap.bitmask.services.eip.udstelnet import UDSTelnet
from leap.bitmask.util import first, force_eval
@@ -145,7 +146,7 @@ class VPN(object):
demand.
"""
TERMINATE_MAXTRIES = 10
- TERMINATE_WAIT = 1 # secs
+ TERMINATE_WAIT = 2 # secs
OPENVPN_VERB = "openvpn_verb"
@@ -173,7 +174,8 @@ class VPN(object):
:param kwargs: kwargs to be passed to the VPNProcess
:type kwargs: dict
"""
- logger.debug('VPN: start')
+ logger.debug(
+ 'VPN: start ---------------------------------------------------')
self._user_stopped = False
self._stop_pollers()
kwargs['openvpn_verb'] = self._openvpn_verb
@@ -181,23 +183,6 @@ class VPN(object):
restart = kwargs.pop('restart', False)
- # start the main vpn subprocess
- vpnproc = VPNProcess(*args, **kwargs)
-
- if vpnproc.get_openvpn_process():
- logger.info("Another vpn process is running. Will try to stop it.")
- vpnproc.stop_if_already_running()
-
- # we try to bring the firewall up
- if IS_LINUX:
- gateways = vpnproc.getGateways()
- 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
-
# FIXME it would be good to document where the
# errors here are catched, since we currently handle them
# at the frontend layer. This *should* move to be handled entirely
@@ -211,17 +196,54 @@ class VPN(object):
# the ping-pong to the frontend, and without adding any logical checks
# in the frontend. We should just communicate UI changes to frontend,
# and abstract us away from anything else.
- try:
+
+ # TODO factor this out to the platform-launchers
+
+ if IS_LINUX:
+ # start the main vpn subprocess
+ vpnproc = VPNProcess(*args, **kwargs)
cmd = vpnproc.getCommand()
- except Exception as e:
- logger.error("Error while getting vpn command... {0!r}".format(e))
- raise
+
+ if vpnproc.get_openvpn_process():
+ logger.info(
+ "Another vpn process is running. Will try to stop it.")
+ vpnproc.stop_if_already_running()
+
+ # we try to bring the firewall up
+ gateways = vpnproc.getGateways()
+ firewall_up = self._launch_firewall_linux(
+ gateways, restart=restart)
+ if not restart and not firewall_up:
+ logger.error("Could not bring firewall up, "
+ "aborting openvpn launch.")
+ return
+
+ if IS_MAC:
+ # start the main vpn subprocess
+ vpnproc = VPNCanary(*args, **kwargs)
+
+ # we try to bring the firewall up
+ gateways = vpnproc.getGateways()
+ firewall_up = self._launch_firewall_osx(
+ gateways, restart=restart)
+ if not restart and not firewall_up:
+ logger.error("Could not bring firewall up, "
+ "aborting openvpn launch.")
+ return
+
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ cmd = vpnproc.getVPNCommand()
+ result = helper.send('openvpn_start %s' % ' '.join(cmd))
+
+ # TODO Windows version -- should be similar to osx.
env = os.environ
for key, val in vpnproc.vpn_env.items():
env[key] = val
- reactor.spawnProcess(vpnproc, cmd[0], cmd, env)
+ cmd = vpnproc.getCommand()
+ running_proc = reactor.spawnProcess(vpnproc, cmd[0], cmd, env)
+ vpnproc.pid = running_proc.pid
self._vpnproc = vpnproc
# add pollers for status and state
@@ -233,9 +255,9 @@ class VPN(object):
self._pollers.extend(poll_list)
self._start_pollers()
- def _launch_firewall(self, gateways, restart=False):
+ def _launch_firewall_linux(self, gateways, restart=False):
"""
- Launch the firewall using the privileged wrapper.
+ Launch the firewall using the privileged wrapper (linux).
:param gateways:
:type gateways: list
@@ -254,40 +276,65 @@ class VPN(object):
exitCode = subprocess.call(cmd + gateways)
return True if exitCode is 0 else False
+ def _launch_firewall_osx(self, gateways, restart=False):
+ cmd = 'firewall_start %s' % ' '.join(gateways)
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ result = helper.send(cmd)
+ return True
+
+ # TODO -- write LINUX/OSX VERSION too ------------------------------------
def is_fw_down(self):
"""
Return whether the firewall is down or not.
:rtype: bool
"""
- BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
- fw_up_cmd = "pkexec {0} firewall isup".format(BM_ROOT)
- fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
- return fw_is_down()
+ if IS_LINUX:
+ BM_ROOT = force_eval(
+ linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
+ fw_up_cmd = "pkexec {0} firewall isup".format(BM_ROOT)
+ fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
+ return fw_is_down()
+
+ if IS_MAC:
+ cmd = 'firewall_isup'
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ result = helper.send(cmd)
+ return True
def tear_down_firewall(self):
"""
Tear the firewall down using the privileged wrapper.
"""
if IS_MAC:
- # We don't support Mac so far
+ cmd = 'firewall_stop'
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ result = helper.send(cmd)
return True
- BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
- exitCode = subprocess.call(["pkexec",
- BM_ROOT, "firewall", "stop"])
- return True if exitCode is 0 else False
+
+ if IS_LINUX:
+ BM_ROOT = force_eval(
+ linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
+ exitCode = subprocess.call(["pkexec",
+ BM_ROOT, "firewall", "stop"])
+ return True if exitCode is 0 else False
def bitmask_root_vpn_down(self):
"""
Bring openvpn down using the privileged wrapper.
"""
if IS_MAC:
- # We don't support Mac so far
+ cmd = 'openvpn_stop'
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ result = helper.send(cmd)
return True
- BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
- exitCode = subprocess.call(["pkexec",
- BM_ROOT, "openvpn", "stop"])
- return True if exitCode is 0 else False
+
+ if IS_LINUX:
+ BM_ROOT = force_eval(
+ linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
+ exitCode = subprocess.call(["pkexec",
+ BM_ROOT, "openvpn", "stop"])
+ return True if exitCode is 0 else False
def _kill_if_left_alive(self, tries=0):
"""
@@ -297,18 +344,18 @@ class VPN(object):
:param tries: counter of tries, used in recursion
:type tries: int
"""
+ # we try to tear the firewall down
+ if (IS_LINUX or IS_MAC) and self._user_stopped:
+ logger.debug('trying to bring firewall down...')
+ firewall_down = self.tear_down_firewall()
+ if firewall_down:
+ logger.debug("Firewall down")
+ else:
+ logger.warning("Could not tear firewall down")
+
while tries < self.TERMINATE_MAXTRIES:
if self._vpnproc.transport.pid is None:
logger.debug("Process has been happily terminated.")
-
- # we try to tear the firewall down
- if IS_LINUX and self._user_stopped:
- firewall_down = self.tear_down_firewall()
- if firewall_down:
- logger.debug("Firewall down")
- else:
- logger.warning("Could not tear firewall down")
-
return
else:
logger.debug("Process did not die, waiting...")
@@ -813,6 +860,8 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
programmatically.
"""
+ pid = None
+
def __init__(self, eipconfig, providerconfig, socket_host, socket_port,
signaler, openvpn_verb):
"""
@@ -861,7 +910,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
self._vpn_observer = VPNObserver(signaler)
self.is_restart = False
- # processProtocol methods
+ # ProcessProtocol methods
def connectionMade(self):
"""
@@ -893,8 +942,11 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
.. seeAlso: `http://twistedmatrix.com/documents/13.0.0/api/twisted.internet.protocol.ProcessProtocol.html` # noqa
"""
exit_code = reason.value.exitCode
+
if isinstance(exit_code, int):
logger.debug("processExited, status %d" % (exit_code,))
+ else:
+ exit_code = 0
self._signaler.signal(
self._signaler.eip_process_finished, exit_code)
self._alive = False
@@ -976,3 +1028,41 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
self.transport.signalProcess('KILL')
except internet_error.ProcessExitedAlready:
logger.debug('Process Exited Already')
+
+
+class VPNCanary(VPNProcess):
+
+ """
+ This is a Canary Process that does not run openvpn itself, but it's
+ notified by the privileged process when the process dies.
+
+ This is an ugly workaround to allow the qt signals and the processprotocol
+ to live happily together until we refactor EIP out of the qt model
+ completely.
+ """
+
+ def connectionMade(self):
+ VPNProcess.connectionMade(self)
+ reactor.callLater(2, self.registerPID)
+
+ def registerPID(self):
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ cmd = 'openvpn_set_watcher %s' % self.pid
+ result = helper.send(cmd)
+
+ def killProcess(self):
+ helper = darwinvpnlauncher.DarwinHelperCommand()
+ cmd = 'openvpn_force_stop'
+ result = helper.send(cmd)
+
+ def getVPNCommand(self):
+ return VPNProcess.getCommand(self)
+
+ def getCommand(self):
+ canary = '''import sys, signal, time
+def receive_signal(signum, stack):
+ sys.exit()
+signal.signal(signal.SIGTERM, receive_signal)
+while True:
+ time.sleep(60)'''
+ return ['python', '-c', '%s' % canary]
diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py
index 68197d9d..cccbcf14 100644
--- a/src/leap/bitmask/services/mail/conductor.py
+++ b/src/leap/bitmask/services/mail/conductor.py
@@ -18,6 +18,7 @@
Mail Services Conductor
"""
from leap.bitmask.config import flags
+from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.logs.utils import get_logger
from leap.bitmask.gui import statemachines
from leap.bitmask.services.mail import connection as mail_connection
@@ -34,6 +35,7 @@ class IMAPControl(object):
"""
Methods related to IMAP control.
"""
+
def __init__(self):
"""
Initializes smtp variables.
@@ -73,12 +75,13 @@ class IMAPControl(object):
self._backend.imap_stop_service()
- def _handle_imap_events(self, event, content):
+ def _handle_imap_events(self, event, userid=None, content=None):
"""
Callback handler for the IMAP events
:param event: The event that triggered the callback.
:type event: str
+ :param userid: The user id of the logged in user. Ignored.
:param content: The content of the event.
:type content: list
"""
@@ -113,10 +116,11 @@ class IMAPControl(object):
"""
Callback for IMAP failed state.
"""
- self.imap_connection.qtsigs.connetion_aborted_signal.emit()
+ self.imap_connection.qtsigs.connection_aborted_signal.emit()
class SMTPControl(object):
+
def __init__(self):
"""
Initializes smtp variables.
@@ -189,7 +193,17 @@ class SMTPControl(object):
self.smtp_connection.qtsigs.connection_aborted_signal.emit()
-class MailConductor(IMAPControl, SMTPControl):
+class PixelatedControl(object):
+
+ def start_pixelated_service(self):
+ self._backend.pixelated_start_service(
+ full_user_id=self.userid)
+
+ def stop_pixelated_service(self):
+ pass
+
+
+class MailConductor(IMAPControl, SMTPControl, PixelatedControl):
"""
This class encapsulates everything related to the initialization and
process control for the mail services.
@@ -266,6 +280,11 @@ class MailConductor(IMAPControl, SMTPControl):
self.start_smtp_service(download_if_needed=download_if_needed)
self.start_imap_service()
+ settings = LeapSettings()
+ pixelmail = settings.get_pixelmail_enabled()
+ if pixelmail:
+ self.start_pixelated_service()
+
self._mail_services_started = True
def stop_mail_services(self):
diff --git a/src/leap/bitmask/services/mail/imap.py b/src/leap/bitmask/services/mail/imap.py
index 5934756d..7875a4af 100644
--- a/src/leap/bitmask/services/mail/imap.py
+++ b/src/leap/bitmask/services/mail/imap.py
@@ -20,11 +20,14 @@ Initialization of imap service
import os
import sys
+from twisted.python import log
+
from leap.bitmask.logs.utils import get_logger
from leap.mail.constants import INBOX_NAME
from leap.mail.imap.service import imap
from leap.mail.incoming.service import IncomingMail, INCOMING_CHECK_PERIOD
-from twisted.python import log
+from leap.mail.mail import Account
+
logger = get_logger()
@@ -57,11 +60,13 @@ def get_mail_check_period():
return period
-def start_imap_service(*args, **kwargs):
+def start_imap_service(soledad_sessions):
"""
Initializes and run imap service.
- :returns: twisted.internet.task.LoopingCall instance
+ :returns: the port as returned by the reactor when starts listening, and
+ the factory for the protocol.
+ :rtype: tuple
"""
from leap.bitmask.config import flags
logger.debug('Launching imap service')
@@ -70,10 +75,10 @@ def start_imap_service(*args, **kwargs):
log.startLogging(open(flags.MAIL_LOGFILE, 'w'))
log.startLogging(sys.stdout)
- return imap.run_service(*args, **kwargs)
+ return imap.run_service(soledad_sessions)
-def start_incoming_mail_service(keymanager, soledad, imap_factory, userid):
+def start_incoming_mail_service(keymanager, soledad, userid):
"""
Initalizes and starts the incomming mail service.
@@ -81,19 +86,12 @@ def start_incoming_mail_service(keymanager, soledad, imap_factory, userid):
"""
def setUpIncomingMail(inbox):
incoming_mail = IncomingMail(
- keymanager,
- soledad,
- inbox.collection,
- userid,
+ keymanager, soledad,
+ inbox, userid,
check_period=get_mail_check_period())
return incoming_mail
- # XXX: do I really need to know here how to get a mailbox??
- # XXX: ideally, the parent service in mail would take care of initializing
- # the account, and passing the mailbox to the incoming service.
- # In an even better world, we just would subscribe to a channel that would
- # pass us the serialized object to be inserted.
- acc = imap_factory.theAccount
- d = acc.callWhenReady(lambda _: acc.getMailbox(INBOX_NAME))
+ acc = Account(soledad, userid)
+ d = acc.callWhenReady(lambda _: acc.get_collection_by_mailbox(INBOX_NAME))
d.addCallback(setUpIncomingMail)
return d
diff --git a/src/leap/bitmask/services/mail/imapcontroller.py b/src/leap/bitmask/services/mail/imapcontroller.py
index 5053d897..855fb74b 100644
--- a/src/leap/bitmask/services/mail/imapcontroller.py
+++ b/src/leap/bitmask/services/mail/imapcontroller.py
@@ -60,9 +60,9 @@ class IMAPController(object):
"""
logger.debug('Starting imap service')
+ soledad_sessions = {userid: self._soledad}
self.imap_port, self.imap_factory = imap.start_imap_service(
- self._soledad,
- userid=userid)
+ soledad_sessions)
def start_and_assign_incoming_service(incoming_mail):
# this returns a deferred that will be called when the looping call
@@ -74,9 +74,7 @@ class IMAPController(object):
if offline is False:
d = imap.start_incoming_mail_service(
- self._keymanager,
- self._soledad,
- self.imap_factory,
+ self._keymanager, self._soledad,
userid)
d.addCallback(start_and_assign_incoming_service)
d.addErrback(lambda f: logger.error(f.printTraceback()))
diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py
index 43203f0c..cd1f06bb 100644
--- a/src/leap/bitmask/services/mail/plumber.py
+++ b/src/leap/bitmask/services/mail/plumber.py
@@ -60,6 +60,7 @@ def initialize_soledad(uuid, email, passwd,
cert_file = ""
class Mock(object):
+
def __init__(self, return_value=None):
self._return = return_value
@@ -140,7 +141,7 @@ class MBOXPlumber(object):
self.sol = initialize_soledad(
self.uuid, self.userid, self.passwd,
secrets, localdb, "/tmp", "/tmp")
- self.acct = IMAPAccount(self.userid, self.sol)
+ self.acct = IMAPAccount(self.sol, self.userid)
return True
#
diff --git a/src/leap/bitmask/services/mail/smtpbootstrapper.py b/src/leap/bitmask/services/mail/smtpbootstrapper.py
index a577509e..f73687a7 100644
--- a/src/leap/bitmask/services/mail/smtpbootstrapper.py
+++ b/src/leap/bitmask/services/mail/smtpbootstrapper.py
@@ -19,6 +19,7 @@ SMTP bootstrapping
"""
import os
import warnings
+from collections import namedtuple
from requests.exceptions import HTTPError
@@ -28,7 +29,6 @@ from leap.bitmask.logs.utils import get_logger
from leap.bitmask.services import download_service_config
from leap.bitmask.services.abstractbootstrapper import AbstractBootstrapper
from leap.bitmask.services.mail.smtpconfig import SMTPConfig
-from leap.bitmask.util import is_file
from leap.common import certs as leap_certs
from leap.common.check import leap_assert
@@ -92,11 +92,13 @@ class SMTPBootstrapper(AbstractBootstrapper):
client_cert_path = self._smtp_config.get_client_cert_path(
self._userid, self._provider_config, about_to_download=True)
- if not is_file(client_cert_path):
+ needs_download = leap_certs.should_redownload(client_cert_path)
+
+ if needs_download:
# For re-download if something is wrong with the cert
+ # FIXME this doesn't read well. should reword the logic here.
self._download_if_needed = (
- self._download_if_needed and
- not leap_certs.should_redownload(client_cert_path))
+ self._download_if_needed and not needs_download)
if self._download_if_needed and os.path.isfile(client_cert_path):
check_and_fix_urw_only(client_cert_path)
@@ -127,9 +129,6 @@ class SMTPBootstrapper(AbstractBootstrapper):
Start the smtp service using the downloaded configurations.
"""
# TODO Make the encrypted_only configurable
- # TODO pick local smtp port in a better way
- # TODO remove hard-coded port and let leap.mail set
- # the specific default.
# TODO handle more than one host and define how to choose
hosts = self._smtp_config.get_hosts()
hostname = hosts.keys()[0]
@@ -138,19 +137,25 @@ class SMTPBootstrapper(AbstractBootstrapper):
client_cert_path = self._smtp_config.get_client_cert_path(
self._userid, self._provider_config, about_to_download=True)
- from leap.mail.smtp import setup_smtp_gateway
+ # XXX this should be defined in leap.mail.smtp, it's in bitmask.core
+ # right now.
+ SendmailOpts = namedtuple(
+ 'SendmailOpts', ['cert', 'key', 'hostname', 'port'])
+
+ userid = self._userid
+ soledad_sessions = {userid: self._soledad}
+ keymanager_sessions = {userid: self._keymanager}
+
+ key = cert = client_cert_path
+ opts = SendmailOpts(cert, key, host, port)
+ sendmail_opts = {userid: opts}
- self._smtp_service, self._smtp_port = setup_smtp_gateway(
- port=2013,
- userid=self._userid,
- keymanager=self._keymanager,
- smtp_host=host,
- smtp_port=port,
- smtp_cert=client_cert_path,
- smtp_key=client_cert_path,
- encrypted_only=False)
+ from leap.mail.smtp import run_service
+ self._smtp_service, self._smtp_port = run_service(
+ soledad_sessions, keymanager_sessions, sendmail_opts)
- def start_smtp_service(self, keymanager, userid, download_if_needed=False):
+ def start_smtp_service(self, soledad, keymanager, userid,
+ download_if_needed=False):
"""
Starts the SMTP service.
@@ -170,6 +175,7 @@ class SMTPBootstrapper(AbstractBootstrapper):
raise MalformedUserId()
self._provider_config = ProviderConfig.get_provider_config(domain)
+ self._soledad = soledad
self._keymanager = keymanager
self._smtp_config = SMTPConfig()
self._userid = str(userid)
diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
index 60a2130b..21cdee31 100644
--- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py
+++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
@@ -331,6 +331,9 @@ class SoledadBootstrapper(AbstractBootstrapper):
:returns: the server url
:rtype: unicode
"""
+ if not self._soledad_config:
+ self._soledad_config = SoledadConfig()
+
# TODO: Select server based on timezone (issue #3308)
server_dict = self._soledad_config.get_hosts()
@@ -654,7 +657,7 @@ class Syncer(object):
logger.error('Invalid auth token while trying to sync Soledad')
self._signaler.signal(
self._signaler.soledad_invalid_auth_token)
- self._callback_deferred.fail(failure)
+ self._callback_deferred.errback(failure)
elif failure.check(sqlite_ProgrammingError,
sqlcipher_ProgrammingError):
logger.exception("%r" % (failure.value,))