summaryrefslogtreecommitdiff
path: root/src/leap
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2015-02-11 23:46:42 -0400
committerIvan Alejandro <ivanalejandro0@gmail.com>2015-02-13 14:01:45 -0300
commite52f9a239a146c06a0683e47eaf9d53f4deb332b (patch)
tree888f58e1e43c324147abe2d64295f3921beb0be7 /src/leap
parentc8b5865364ffabc5400642684050286c5c836352 (diff)
enable --offline mode for email again
Diffstat (limited to 'src/leap')
-rw-r--r--src/leap/bitmask/app.py17
-rw-r--r--src/leap/bitmask/backend/backend_proxy.py3
-rw-r--r--src/leap/bitmask/backend/components.py5
-rw-r--r--src/leap/bitmask/backend/settings.py27
-rw-r--r--src/leap/bitmask/config/leapsettings.py32
-rw-r--r--src/leap/bitmask/gui/mainwindow.py10
-rw-r--r--src/leap/bitmask/services/soledad/soledadbootstrapper.py116
-rw-r--r--src/leap/bitmask/util/leap_argparse.py41
8 files changed, 117 insertions, 134 deletions
diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index 9056d2a6..72c03cb9 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -127,9 +127,7 @@ def start_app():
}
flags.STANDALONE = opts.standalone
- # XXX Disabled right now since it's not tested after login refactor
- # flags.OFFLINE = opts.offline
- flags.OFFLINE = False
+ flags.OFFLINE = opts.offline
flags.MAIL_LOGFILE = opts.mail_log_file
flags.APP_VERSION_CHECK = opts.app_version_check
flags.API_VERSION_CHECK = opts.api_version_check
@@ -139,16 +137,19 @@ def start_app():
flags.CA_CERT_FILE = opts.ca_cert_file
replace_stdout = True
- if opts.repair or opts.import_maildir:
- # We don't want too much clutter on the comand mode
- # this could be more generic with a Command class.
- replace_stdout = False
+
+ # XXX mail repair commands disabled for now
+ # if opts.repair or opts.import_maildir:
+ # We don't want too much clutter on the comand mode
+ # this could be more generic with a Command class.
+ # replace_stdout = False
logger = create_logger(opts.debug, opts.log_file, replace_stdout)
# ok, we got logging in place, we can satisfy mail plumbing requests
# and show logs there. it normally will exit there if we got that path.
- do_mail_plumbing(opts)
+ # XXX mail repair commands disabled for now
+ # do_mail_plumbing(opts)
try:
event_server.ensure_server(event_server.SERVER_PORT)
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index 3e79289f..e9ad9b4d 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -28,6 +28,7 @@ import time
import zmq
from leap.bitmask.backend.api import API, STOP_REQUEST, PING_REQUEST
+from leap.bitmask.backend.settings import Settings
from leap.bitmask.backend.utils import generate_zmq_certificates_if_needed
from leap.bitmask.backend.utils import get_backend_certificates
@@ -54,6 +55,8 @@ class BackendProxy(object):
self._socket = None
+ self.settings = Settings()
+
# initialize ZMQ stuff:
context = zmq.Context()
logger.debug("Connecting to server...")
diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index 2ae796f6..a843147e 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -779,6 +779,8 @@ class Soledad(object):
"""
provider_config = ProviderConfig.get_provider_config(domain)
if provider_config is not None:
+ # XXX FIXME --- remove defer-to-thread or at least put it in a
+ # separate threadpool.
self._soledad_defer = threads.deferToThread(
self._soledad_bootstrapper.run_soledad_setup_checks,
provider_config, username, password,
@@ -816,8 +818,9 @@ class Soledad(object):
Signaler.soledad_offline_finished
Signaler.soledad_offline_failed
"""
- self._soledad_bootstrapper.load_offline_soledad(
+ d = self._soledad_bootstrapper.load_offline_soledad(
username, password, uuid)
+ d.addCallback(self._set_proxies_cb)
def cancel_bootstrap(self):
"""
diff --git a/src/leap/bitmask/backend/settings.py b/src/leap/bitmask/backend/settings.py
index 5cb4c616..ed70ca6b 100644
--- a/src/leap/bitmask/backend/settings.py
+++ b/src/leap/bitmask/backend/settings.py
@@ -122,37 +122,36 @@ class Settings(object):
self._settings.set(provider, self.GATEWAY_KEY, gateway)
self._save()
- def get_uuid(self, username):
+ def get_uuid(self, full_user_id):
"""
Gets the uuid for a given username.
- :param username: the full user identifier in the form user@provider
- :type username: basestring
+ :param full_user_id: the full user identifier in the form user@provider
+ :type full_user_id: basestring
"""
- leap_assert("@" in username,
+ leap_assert("@" in full_user_id,
"Expected username in the form user@provider")
- user, provider = username.split('@')
+ username, provider = full_user_id.split('@')
+ return self._get_value(provider, full_user_id, "")
- return self._get_value(provider, username, "")
-
- def set_uuid(self, username, value):
+ def set_uuid(self, full_user_id, value):
"""
Sets the uuid for a given username.
- :param username: the full user identifier in the form user@provider
- :type username: str or unicode
+ :param full_user_id: the full user identifier in the form user@provider
+ :type full_user_id: str or unicode
:param value: the uuid to save or None to remove it
:type value: str or unicode or None
"""
- leap_assert("@" in username,
+ leap_assert("@" in full_user_id,
"Expected username in the form user@provider")
- user, provider = username.split('@')
+ user, provider = full_user_id.split('@')
if value is None:
- self._settings.remove_option(provider, username)
+ self._settings.remove_option(provider, full_user_id)
else:
leap_assert(len(value) > 0, "We cannot save an empty uuid")
self._add_section(provider)
- self._settings.set(provider, username, value)
+ self._settings.set(provider, full_user_id, value)
self._save()
diff --git a/src/leap/bitmask/config/leapsettings.py b/src/leap/bitmask/config/leapsettings.py
index 13a1e99e..fd3e1592 100644
--- a/src/leap/bitmask/config/leapsettings.py
+++ b/src/leap/bitmask/config/leapsettings.py
@@ -353,35 +353,3 @@ class LeapSettings(object):
"""
leap_assert_type(skip, bool)
self._settings.setValue(self.SKIPFIRSTRUN_KEY, skip)
-
- def get_uuid(self, username):
- """
- Gets the uuid for a given username.
-
- :param username: the full user identifier in the form user@provider
- :type username: basestring
- """
- leap_assert("@" in username,
- "Expected username in the form user@provider")
- user, provider = username.split('@')
- return self._settings.value(
- self.UUIDFORUSER_KEY % (provider, user), "")
-
- def set_uuid(self, username, value):
- """
- Sets the uuid for a given username.
-
- :param username: the full user identifier in the form user@provider
- :type username: str or unicode
- :param value: the uuid to save or None to remove it
- :type value: str or unicode or None
- """
- leap_assert("@" in username,
- "Expected username in the form user@provider")
- user, provider = username.split('@')
- key = self.UUIDFORUSER_KEY % (provider, user)
- if value is None:
- self._settings.remove(key)
- else:
- leap_assert(len(value) > 0, "We cannot save an empty uuid")
- self._settings.setValue(key, value)
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 808b0410..35253ebe 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -126,6 +126,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
self._backend = self.app.backend
self._leap_signaler = self.app.signaler
self._settings = self.app.settings
+ self._backend_settings = self._backend.settings
# Login Widget
self._login_widget = LoginWidget(self._backend,
@@ -1191,8 +1192,9 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
user = self._login_widget.get_logged_user()
# XXX the widget now gives us the full user id.
# this is confusing.
- #domain = self._providers.get_selected_provider()
- #full_user_id = make_address(user, domain)
+ # domain = self._providers.get_selected_provider()
+ # full_user_id = make_address(user, domain)
+
# XXX the casting to str (needed by smtp gateway) should be done
# in a better place.
self._mail_conductor.userid = str(user)
@@ -1313,10 +1315,10 @@ class MainWindow(QtGui.QMainWindow, SignalTracker):
if flags.OFFLINE:
full_user_id = make_address(username, provider_domain)
- uuid = self._settings.get_uuid(full_user_id)
+ uuid = self._backend_settings.get_uuid(full_user_id)
self._mail_conductor.userid = full_user_id
- if uuid is None:
+ if not uuid:
# We don't need more visibility at the moment,
# this is mostly for internal use/debug for now.
logger.warning("Sorry! Log-in at least one time.")
diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
index 045b2e19..e8946fa4 100644
--- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py
+++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
@@ -28,6 +28,7 @@ from sqlite3 import ProgrammingError as sqlite_ProgrammingError
from u1db import errors as u1db_errors
from twisted.internet import threads, defer
+import zope.proxy
from zope.proxy import sameProxiedObjects
from pysqlcipher.dbapi2 import ProgrammingError as sqlcipher_ProgrammingError
@@ -59,31 +60,6 @@ They should not be needed after we allow a null remote initialization in the
soledad client, and a switch to remote sync-able mode during runtime.
"""
-
-class Mock(object):
- """
- A generic simple mock class
- """
- def __init__(self, return_value=None):
- self._return = return_value
-
- def __call__(self, *args, **kwargs):
- return self._return
-
-
-class MockSharedDB(object):
- """
- Mocked SharedDB object to replace in soledad before
- instantiating it in offline mode.
- """
- get_doc = Mock()
- put_doc = Mock()
- lock = Mock(return_value=('atoken', 300))
- unlock = Mock(return_value=True)
-
- def __call__(self):
- return self
-
# TODO these exceptions could be moved to soledad itself
# after settling this down.
@@ -146,7 +122,6 @@ class SoledadBootstrapper(AbstractBootstrapper):
self._provider_config = None
self._soledad_config = None
- self._keymanager = None
self._download_if_needed = False
self._user = ""
@@ -155,7 +130,9 @@ class SoledadBootstrapper(AbstractBootstrapper):
self._uuid = ""
self._srpauth = None
- self._soledad = None
+
+ self._soledad = zope.proxy.ProxyBase(None)
+ self._keymanager = zope.proxy.ProxyBase(None)
@property
def keymanager(self):
@@ -190,9 +167,13 @@ class SoledadBootstrapper(AbstractBootstrapper):
self._password = password
self._uuid = uuid
try:
- self.load_and_sync_soledad(uuid, offline=True)
- self._signaler.signal(self._signaler.soledad_offline_finished)
+ d = self.load_and_sync_soledad(uuid, offline=True)
+ d.addCallback(
+ lambda _: self._signaler.signal(
+ self._signaler.soledad_offline_finished))
+ return d
except Exception as e:
+ # XXX convert exception into failure.trap
# TODO: we should handle more specific exceptions in here
logger.exception(e)
self._signaler.signal(self._signaler.soledad_offline_failed)
@@ -248,7 +229,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
# warned the user in _do_soledad_sync()
def _do_soledad_init(self, uuid, secrets_path, local_db_path,
- server_url, cert_file, token):
+ server_url, cert_file, token, syncable):
"""
Initialize soledad, retry if necessary and raise an exception if we
can't succeed.
@@ -274,7 +255,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
logger.debug("Trying to init soledad....")
self._try_soledad_init(
uuid, secrets_path, local_db_path,
- server_url, cert_file, token)
+ server_url, cert_file, token, syncable)
logger.debug("Soledad has been initialized.")
return
except Exception as exc:
@@ -296,6 +277,8 @@ class SoledadBootstrapper(AbstractBootstrapper):
:type uuid: unicode, or None.
:param offline: whether to instantiate soledad for offline use.
:type offline: bool
+
+ :rtype: defer.Deferred
"""
local_param = self._get_soledad_local_params(uuid, offline)
remote_param = self._get_soledad_server_params(uuid, offline)
@@ -303,21 +286,26 @@ class SoledadBootstrapper(AbstractBootstrapper):
secrets_path, local_db_path, token = local_param
server_url, cert_file = remote_param
- try:
- self._do_soledad_init(uuid, secrets_path, local_db_path,
- server_url, cert_file, token)
- except SoledadInitError:
- # re-raise the exceptions from try_init,
- # we're currently handling the retries from the
- # soledad-launcher in the gui.
- raise
-
- leap_assert(not sameProxiedObjects(self._soledad, None),
- "Null soledad, error while initializing")
+ if offline:
+ return self._load_soledad_nosync(
+ uuid, secrets_path, local_db_path, cert_file, token)
- if flags.OFFLINE:
- self._init_keymanager(self._address, token)
else:
+ # We assume online operation from here on.
+ # XXX split in subfunction
+ syncable = True
+ try:
+ self._do_soledad_init(uuid, secrets_path, local_db_path,
+ server_url, cert_file, token, syncable)
+ except SoledadInitError:
+ # re-raise the exceptions from try_init,
+ # we're currently handling the retries from the
+ # soledad-launcher in the gui.
+ raise
+
+ leap_assert(not sameProxiedObjects(self._soledad, None),
+ "Null soledad, error while initializing")
+
address = make_address(
self._user, self._provider_config.get_domain())
@@ -335,9 +323,21 @@ class SoledadBootstrapper(AbstractBootstrapper):
address, openpgp.OpenPGPKey,
private=True, fetch_remote=False))
d.addCallbacks(
+ # XXX WTF --- FIXME remove this call to thread, soledad already
+ # does the sync in its own threadpool. -- kali
lambda _: threads.deferToThread(self._do_soledad_sync),
key_not_found)
d.addErrback(self._soledad_sync_errback)
+ return d
+
+ def _load_soledad_nosync(self, uuid, secrets_path, local_db_path,
+ cert_file, token):
+
+ syncable = False
+ self._do_soledad_init(uuid, secrets_path, local_db_path,
+ "", cert_file, token, syncable)
+ d = self._init_keymanager(self._address, token)
+ return d
def _pick_server(self, uuid):
"""
@@ -410,7 +410,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
raise SoledadSyncError()
def _try_soledad_init(self, uuid, secrets_path, local_db_path,
- server_url, cert_file, auth_token):
+ server_url, cert_file, auth_token, syncable):
"""
Try to initialize soledad.
@@ -433,9 +433,6 @@ class SoledadBootstrapper(AbstractBootstrapper):
# (issue #3309)
encoding = sys.getfilesystemencoding()
- # XXX We should get a flag in soledad itself
- if flags.OFFLINE is True:
- Soledad._shared_db = MockSharedDB()
try:
self._soledad = Soledad(
uuid,
@@ -445,7 +442,8 @@ class SoledadBootstrapper(AbstractBootstrapper):
server_url=server_url,
cert_file=cert_file.encode(encoding),
auth_token=auth_token,
- defer_encryption=True)
+ defer_encryption=True,
+ syncable=syncable)
# XXX All these errors should be handled by soledad itself,
# and return a subclass of SoledadInitializationFailed
@@ -668,7 +666,9 @@ class SoledadBootstrapper(AbstractBootstrapper):
self._user = user
self._password = password
- if flags.OFFLINE:
+ is_offline = flags.OFFLINE
+
+ if is_offline:
signal_finished = self._signaler.soledad_offline_finished
signal_failed = self._signaler.soledad_offline_failed
else:
@@ -676,17 +676,23 @@ class SoledadBootstrapper(AbstractBootstrapper):
signal_failed = self._signaler.soledad_bootstrap_failed
try:
- self._download_config()
+ if not is_offline:
+ # XXX FIXME make this async too! (use txrequests)
+ # Also, why the fuck would we want to download it *every time*?
+ # We should be fine by using last-time config, or at least
+ # trying it.
+ self._download_config()
- # soledad config is ok, let's proceed to load and sync soledad
- uuid = self.srpauth.get_uuid()
- self.load_and_sync_soledad(uuid)
+ # soledad config is ok, let's proceed to load and sync soledad
+ uuid = self.srpauth.get_uuid()
+ self.load_and_sync_soledad(uuid)
- if not flags.OFFLINE:
d = self._gen_key()
d.addCallback(lambda _: self._signaler.signal(signal_finished))
+ return d
else:
self._signaler.signal(signal_finished)
+ return defer.succeed(True)
except Exception as e:
# TODO: we should handle more specific exceptions in here
self._soledad = None
diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py
index 346caed5..12fd9736 100644
--- a/src/leap/bitmask/util/leap_argparse.py
+++ b/src/leap/bitmask/util/leap_argparse.py
@@ -74,26 +74,27 @@ def build_parser():
help='Verbosity level for openvpn logs [1-6]')
# mail stuff
- # XXX Disabled right now since it's not tested after login refactor
- # parser.add_argument('-o', '--offline', action="store_true",
- # help='Starts Bitmask in offline mode: will not '
- # 'try to sync with remote replicas for email.')
-
- parser.add_argument('--acct', metavar="user@provider",
- nargs='?',
- action="store", dest="acct",
- help='Manipulate mailboxes for this account')
- parser.add_argument('-r', '--repair-mailboxes', default=False,
- action="store_true", dest="repair",
- help='Repair mailboxes for a given account. '
- 'Use when upgrading versions after a schema '
- 'change. Use with --acct')
- parser.add_argument('--import-maildir', metavar="/path/to/Maildir",
- nargs='?',
- action="store", dest="import_maildir",
- help='Import the given maildir. Use with the '
- '--to-mbox flag to import to folders other '
- 'than INBOX. Use with --acct')
+ parser.add_argument('-o', '--offline', action="store_true",
+ help='Starts Bitmask in offline mode: will not '
+ 'try to sync with remote replicas for email.')
+
+ # XXX not yet updated to new mail api for mail 0.4.0
+
+ # parser.add_argument('--acct', metavar="user@provider",
+ #nargs='?',
+ #action="store", dest="acct",
+ #help='Manipulate mailboxes for this account')
+ # parser.add_argument('-r', '--repair-mailboxes', default=False,
+ #action="store_true", dest="repair",
+ #help='Repair mailboxes for a given account. '
+ #'Use when upgrading versions after a schema '
+ #'change. Use with --acct')
+ # parser.add_argument('--import-maildir', metavar="/path/to/Maildir",
+ #nargs='?',
+ #action="store", dest="import_maildir",
+ #help='Import the given maildir. Use with the '
+ #'--to-mbox flag to import to folders other '
+ #'than INBOX. Use with --acct')
if not IS_RELEASE_VERSION:
help_text = ("Bypasses the certificate check during provider "