From 37353a2c57a759e160a7060c412b15d30ebde4bb Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 22 May 2014 17:34:24 -0300 Subject: Refactor cleanup, ProviderConfig to backend. --- src/leap/bitmask/backend.py | 161 ++++++++++++---- src/leap/bitmask/config/providerconfig.py | 64 +++++-- src/leap/bitmask/gui/mainwindow.py | 207 +++++++++------------ src/leap/bitmask/gui/preferenceswindow.py | 114 ++++++------ src/leap/bitmask/gui/wizard.py | 73 ++++---- .../services/soledad/soledadbootstrapper.py | 3 +- 6 files changed, 360 insertions(+), 262 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index d6d5004f..e8bf0482 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -37,8 +37,8 @@ from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister from leap.bitmask.platform_init import IS_LINUX -from leap.bitmask.provider import get_provider_path from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper +from leap.bitmask.services import get_supported from leap.bitmask.services.eip import eipconfig from leap.bitmask.services.eip import get_openvpn_management from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper @@ -64,26 +64,6 @@ from PySide import QtCore logger = logging.getLogger(__name__) -def get_provider_config(config, domain): - """ - Return the ProviderConfig object for the given domain. - If it is already loaded in `config`, then don't reload. - - :param config: a ProviderConfig object - :type conig: ProviderConfig - :param domain: the domain which config is required. - :type domain: unicode - - :returns: True if the config was loaded successfully, False otherwise. - :rtype: bool - """ - # TODO: see ProviderConfig.get_provider_config - if (not config.loaded() or config.get_domain() != domain): - config.load(get_provider_path(domain)) - - return config.loaded() - - class ILEAPComponent(zope.interface.Interface): """ Interface that every component for the backend should comply to @@ -167,6 +147,7 @@ class Provider(object): :type bypass_checks: bool """ self.key = "provider" + self._signaler = signaler self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) self._download_provider_defer = None @@ -208,13 +189,9 @@ class Provider(object): """ d = None - # TODO: use this commented code when we don't need the provider config - # in the maiwindow. - # config = ProviderConfig.get_provider_config(provider) - # self._provider_config = config - # if config is not None: - config = self._provider_config - if get_provider_config(config, provider): + config = ProviderConfig.get_provider_config(provider) + self._provider_config = config + if config is not None: d = self._provider_bootstrapper.run_provider_setup_checks( config, download_if_needed=True) else: @@ -228,6 +205,73 @@ class Provider(object): d = defer.Deferred() return d + def _get_services(self, domain): + """ + Returns a list of services provided by the given provider. + + :param domain: the provider to get the services from. + :type domain: str + + :rtype: list of str + """ + services = [] + provider_config = ProviderConfig.get_provider_config(domain) + if provider_config is not None: + services = provider_config.get_services() + + return services + + def get_supported_services(self, domain): + """ + Signal a list of supported services provided by the given provider. + + :param domain: the provider to get the services from. + :type domain: str + + Signals: + prov_get_supported_services -> list of unicode + """ + services = get_supported(self._get_services(domain)) + + self._signaler.signal( + self._signaler.PROV_GET_SUPPORTED_SERVICES, services) + + def get_all_services(self, providers): + """ + Signal a list of services provided by all the configured providers. + + :param providers: the list of providers to get the services. + :type providers: list + + Signals: + prov_get_all_services -> list of unicode + """ + services_all = set() + + for domain in providers: + services = self._get_services(domain) + services_all = services_all.union(set(services)) + + self._signaler.signal( + self._signaler.PROV_GET_ALL_SERVICES, services_all) + + def get_details(self, domain, lang=None): + """ + Signal a ProviderConfigLight object with the current ProviderConfig + settings. + + :param domain: the domain name of the provider. + :type domain: str + :param lang: the language to use for localized strings. + :type lang: str + + Signals: + prov_get_details -> ProviderConfigLight + """ + self._signaler.signal( + self._signaler.PROV_GET_DETAILS, + self._provider_config.get_light_config(domain, lang)) + class Register(object): """ @@ -926,6 +970,10 @@ class Signaler(QtCore.QObject): prov_unsupported_client = QtCore.Signal(object) prov_unsupported_api = QtCore.Signal(object) + prov_get_all_services = QtCore.Signal(object) + prov_get_supported_services = QtCore.Signal(object) + prov_get_details = QtCore.Signal(object) + prov_cancelled_setup = QtCore.Signal(object) # Signals for SRPRegister @@ -1021,6 +1069,9 @@ class Signaler(QtCore.QObject): PROV_UNSUPPORTED_CLIENT = "prov_unsupported_client" PROV_UNSUPPORTED_API = "prov_unsupported_api" PROV_CANCELLED_SETUP = "prov_cancelled_setup" + PROV_GET_ALL_SERVICES = "prov_get_all_services" + PROV_GET_SUPPORTED_SERVICES = "prov_get_supported_services" + PROV_GET_DETAILS = "prov_get_details" SRP_REGISTRATION_FINISHED = "srp_registration_finished" SRP_REGISTRATION_FAILED = "srp_registration_failed" @@ -1106,6 +1157,9 @@ class Signaler(QtCore.QObject): self.PROV_UNSUPPORTED_CLIENT, self.PROV_UNSUPPORTED_API, self.PROV_CANCELLED_SETUP, + self.PROV_GET_ALL_SERVICES, + self.PROV_GET_SUPPORTED_SERVICES, + self.PROV_GET_DETAILS, self.SRP_REGISTRATION_FINISHED, self.SRP_REGISTRATION_FAILED, @@ -1393,6 +1447,47 @@ class Backend(object): """ self._call_queue.put(("provider", "bootstrap", None, provider)) + def provider_get_supported_services(self, domain): + """ + Signal a list of supported services provided by the given provider. + + :param domain: the provider to get the services from. + :type domain: str + + Signals: + prov_get_supported_services -> list of unicode + """ + self._call_queue.put(("provider", "get_supported_services", None, + domain)) + + def provider_get_all_services(self, providers): + """ + Signal a list of services provided by all the configured providers. + + :param providers: the list of providers to get the services. + :type providers: list + + Signals: + prov_get_all_services -> list of unicode + """ + self._call_queue.put(("provider", "get_all_services", None, + providers)) + + def provider_get_details(self, domain, lang): + """ + Signal a ProviderConfigLight object with the current ProviderConfig + settings. + + :param domain: the domain name of the provider. + :type domain: str + :param lang: the language to use for localized strings. + :type lang: str + + Signals: + prov_get_details -> ProviderConfigLight + """ + self._call_queue.put(("provider", "get_details", None, domain, lang)) + def user_register(self, provider, username, password): """ Register a user using the domain and password given as parameters. @@ -1698,16 +1793,6 @@ class Backend(object): # XXX HACK: this section is meant to be a place to hold methods and # variables needed in the meantime while we migrate all to the backend. - def get_provider_config(self): - # TODO: refactor the provider config into a singleton/global loading it - # every time from the file. - provider_config = self._components["provider"]._provider_config - return provider_config - - def get_soledad(self): - soledad = self._components["soledad"]._soledad_bootstrapper._soledad - return soledad - def get_keymanager(self): km = self._components["soledad"]._soledad_bootstrapper._keymanager return km diff --git a/src/leap/bitmask/config/providerconfig.py b/src/leap/bitmask/config/providerconfig.py index b411c6f3..cf31b3b2 100644 --- a/src/leap/bitmask/config/providerconfig.py +++ b/src/leap/bitmask/config/providerconfig.py @@ -38,6 +38,35 @@ class MissingCACert(Exception): pass +class ProviderConfigLight(object): + """ + A light config object to hold some provider settings needed by the GUI. + """ + def __init__(self): + """ + Define the public attributes. + """ + self.domain = "" + self.name = "" + self.description = "" + self.enrollment_policy = "" + self.services = [] + + @property + def services_string(self): + """ + Return a comma separated list of serices provided by this provider. + + :rtype: str + """ + services = [] + for service in self.services: + services.append(get_service_display_name(service)) + + services_str = ", ".join(services) + return services_str + + class ProviderConfig(BaseConfig): """ Provider configuration abstraction class @@ -45,6 +74,29 @@ class ProviderConfig(BaseConfig): def __init__(self): BaseConfig.__init__(self) + def get_light_config(self, domain, lang=None): + """ + Return a ProviderConfigLight object with the data for the loaded + object. + + :param domain: the domain name of the provider. + :type domain: str + :param lang: the language to use for localized strings. + :type lang: str + + :rtype: ProviderConfigLight or None if the ProviderConfig isn't loaded. + """ + config = self.get_provider_config(domain) + details = ProviderConfigLight() + + details.domain = config.get_domain() + details.name = config.get_name(lang=lang) + details.description = config.get_description(lang=lang) + details.enrollment_policy = config.get_enrollment_policy() + details.services = config.get_services() + + return details + @classmethod def get_provider_config(self, domain): """ @@ -144,18 +196,6 @@ class ProviderConfig(BaseConfig): services = self._safe_get_value("services") return services - def get_services_string(self): - """ - Returns a string with the available services in the current - provider, ready to be shown to the user. - """ - services = [] - for service in self.get_services(): - services.append(get_service_display_name(service)) - - services_str = ", ".join(services) - return services_str - def get_ca_cert_path(self, about_to_download=False): """ Returns the path to the certificate for the current provider. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 201a24ec..4d79305e 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -30,7 +30,6 @@ from leap.bitmask import __version__ as VERSION from leap.bitmask import __version_hash__ as VERSION_HASH from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings -from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.gui import statemachines from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement @@ -43,7 +42,6 @@ from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard -from leap.bitmask import provider from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform @@ -64,7 +62,6 @@ if IS_WIN: from leap.bitmask.platform_init.locks import WindowsLock from leap.bitmask.platform_init.locks import raise_window_ack -from leap.common.check import leap_assert from leap.common.events import register from leap.common.events import events_pb2 as proto @@ -178,15 +175,6 @@ class MainWindow(QtGui.QMainWindow): self._trying_to_start_eip = False - # This is loaded only once, there's a bug when doing that more - # than once - # XXX HACK!! But we need it as long as we are using - # provider_config in here - self._provider_config = self._backend.get_provider_config() - - # Used for automatic start of EIP - self._provisional_provider_config = ProviderConfig() - self._already_started_eip = False self._soledad_started = False @@ -247,6 +235,8 @@ class MainWindow(QtGui.QMainWindow): self._ui_mx_visible = True self._ui_eip_visible = True + self._provider_details = None + # last minute UI manipulations self._center_window() @@ -383,6 +373,9 @@ class MainWindow(QtGui.QMainWindow): self._connect_and_track(sig.prov_cancelled_setup, self._set_login_cancelled) + self._connect_and_track(sig.prov_get_details, + self._provider_get_details) + # Login signals self._connect_and_track(sig.srp_auth_ok, self._authentication_finished) @@ -430,9 +423,14 @@ class MainWindow(QtGui.QMainWindow): sig.backend_bad_call.connect(self._backend_bad_call) + sig.prov_check_api_certificate.connect(self._get_provider_details) + sig.prov_unsupported_client.connect(self._needs_update) sig.prov_unsupported_api.connect(self._incompatible_api) + sig.prov_get_all_services.connect( + self._provider_get_all_services) + # EIP start signals sig.eip_openvpn_already_running.connect( self._on_eip_openvpn_already_running) @@ -597,12 +595,13 @@ class MainWindow(QtGui.QMainWindow): domain = self._login_widget.get_selected_provider() logged_user = "{0}@{1}".format(self._logged_user, domain) - has_mx = True - if self._logged_user is not None: - provider_config = self._get_best_provider_config() - has_mx = provider_config.provides_mx() + details = self._provider_details + mx_provided = False + if details is not None: + mx_provided = MX_SERVICE in details - akm = AdvancedKeyManagement(self, has_mx, logged_user, + # XXX: handle differently not logged in user? + akm = AdvancedKeyManagement(self, mx_provided, logged_user, self._keymanager, self._soledad_started) akm.show() @@ -618,8 +617,7 @@ class MainWindow(QtGui.QMainWindow): user = self._login_widget.get_user() prov = self._login_widget.get_selected_provider() preferences = PreferencesWindow( - self, self._backend, self._provider_config, - self._soledad_started, user, prov) + self, self._backend, self._soledad_started, user, prov) self.soledad_ready.connect(preferences.set_soledad_ready) preferences.show() @@ -857,16 +855,9 @@ class MainWindow(QtGui.QMainWindow): """ providers = self._settings.get_configured_providers() - services = set() - - for prov in providers: - provider_config = ProviderConfig() - loaded = provider_config.load( - provider.get_provider_path(prov)) - if loaded: - for service in provider_config.get_services(): - services.add(service) + self._backend.provider_get_all_services(providers) + def _provider_get_all_services(self, services): self._set_eip_visible(EIP_SERVICE in services) self._set_mx_visible(MX_SERVICE in services) @@ -904,14 +895,11 @@ class MainWindow(QtGui.QMainWindow): """ Set the login label to reflect offline status. """ - if self._logged_in_offline: - provider = "" - else: + provider = "" + if not self._logged_in_offline: provider = self.ui.lblLoginProvider.text() - self.ui.lblLoginProvider.setText( - provider + - self.tr(" (offline mode)")) + self.ui.lblLoginProvider.setText(provider + self.tr(" (offline mode)")) # # systray @@ -1165,9 +1153,8 @@ class MainWindow(QtGui.QMainWindow): provider configuration if it's not present, otherwise will emit the corresponding signals inmediately """ - # XXX should rename this provider, name clash. - provider = self._login_widget.get_selected_provider() - self._backend.provider_setup(provider) + domain = self._login_widget.get_selected_provider() + self._backend.provider_setup(domain) @QtCore.Slot(dict) def _load_provider_config(self, data): @@ -1175,12 +1162,11 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._backend.signaler.prov_download_provider_info - Once the provider config has been downloaded, this loads the - self._provider_config instance with it and starts the second - part of the bootstrapping sequence + Once the provider config has been downloaded, start the second + part of the bootstrapping sequence. :param data: result from the last stage of the - run_provider_select_checks + backend.provider_setup() :type data: dict """ if data[self._backend.PASSED_KEY]: @@ -1222,7 +1208,6 @@ class MainWindow(QtGui.QMainWindow): self._set_label_offline() self.offline_mode_bypass_login.emit() else: - leap_assert(self._provider_config, "We need a provider config") self.ui.action_create_new_account.setEnabled(False) if self._login_widget.start_login(): self._download_provider_config() @@ -1290,15 +1275,13 @@ class MainWindow(QtGui.QMainWindow): Once the provider configuration is loaded, this starts the SRP authentication """ - leap_assert(self._provider_config, "We need a provider config!") - if data[self._backend.PASSED_KEY]: username = self._login_widget.get_user() password = self._login_widget.get_password() self._show_hide_unsupported_services() - domain = self._provider_config.get_domain() + domain = self._login_widget.get_selected_provider() self._backend.user_login(domain, username, password) else: logger.error(data[self._backend.ERROR_KEY]) @@ -1317,7 +1300,7 @@ class MainWindow(QtGui.QMainWindow): self._logged_user = self._login_widget.get_user() user = self._logged_user - domain = self._provider_config.get_domain() + domain = self._login_widget.get_selected_provider() full_user_id = make_address(user, domain) self._mail_conductor.userid = full_user_id self._start_eip_bootstrap() @@ -1331,7 +1314,7 @@ class MainWindow(QtGui.QMainWindow): sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True)) sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True)) - if not self._get_best_provider_config().provides_mx(): + if not MX_SERVICE in self._provider_details.services: self._set_mx_visible(False) def _start_eip_bootstrap(self): @@ -1341,11 +1324,10 @@ class MainWindow(QtGui.QMainWindow): """ self._login_widget.logged_in() - provider = self._provider_config.get_domain() - self.ui.lblLoginProvider.setText(provider) + domain = self._login_widget.get_selected_provider() + self.ui.lblLoginProvider.setText(domain) - self._enabled_services = self._settings.get_enabled_services( - self._provider_config.get_domain()) + self._enabled_services = self._settings.get_enabled_services(domain) # TODO separate UI from logic. if self._provides_mx_and_enabled(): @@ -1355,6 +1337,30 @@ class MainWindow(QtGui.QMainWindow): self._maybe_start_eip() + @QtCore.Slot() + def _get_provider_details(self): + """ + TRIGGERS: + prov_check_api_certificate + + Set the attributes to know if the EIP and MX services are supported + and enabled. + This is triggered right after the provider has been set up. + """ + domain = self._login_widget.get_selected_provider() + lang = QtCore.QLocale.system().name() + self._backend.provider_get_details(domain, lang) + + @QtCore.Slot() + def _provider_get_details(self, details): + """ + Set the details for the just downloaded provider. + + :param details: the details of the provider. + :type details: ProviderConfigLight + """ + self._provider_details = details + def _provides_mx_and_enabled(self): """ Defines if the current provider provides mx and if we have it enabled. @@ -1362,9 +1368,15 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - provider_config = self._get_best_provider_config() - return (provider_config.provides_mx() and - MX_SERVICE in self._enabled_services) + domain = self._login_widget.get_selected_provider() + enabled_services = self._settings.get_enabled_services(domain) + + mx_enabled = MX_SERVICE in enabled_services + mx_provided = False + if self._provider_details is not None: + mx_provided = MX_SERVICE in self._provider_details.services + + return mx_enabled and mx_provided def _provides_eip_and_enabled(self): """ @@ -1373,16 +1385,23 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - provider_config = self._get_best_provider_config() - return (provider_config.provides_eip() and - EIP_SERVICE in self._enabled_services) + domain = self._login_widget.get_selected_provider() + enabled_services = self._settings.get_enabled_services(domain) + + eip_enabled = EIP_SERVICE in enabled_services + eip_provided = False + if self._provider_details is not None: + eip_provided = EIP_SERVICE in self._provider_details.services + + return eip_enabled and eip_provided def _maybe_run_soledad_setup_checks(self): """ Conditionally start Soledad. """ # TODO split. - if not self._provides_mx_and_enabled(): + if not self._provides_mx_and_enabled() and not flags.OFFLINE: + logger.debug("Does not provides and enabled MX") return username = self._login_widget.get_user() @@ -1390,9 +1409,6 @@ class MainWindow(QtGui.QMainWindow): provider_domain = self._login_widget.get_selected_provider() if flags.OFFLINE: - self._provisional_provider_config.load( - provider.get_provider_path(provider_domain)) - full_user_id = make_address(username, provider_domain) uuid = self._settings.get_uuid(full_user_id) self._mail_conductor.userid = full_user_id @@ -1405,7 +1421,7 @@ class MainWindow(QtGui.QMainWindow): self._backend.soledad_load_offline(full_user_id, password, uuid) else: if self._logged_user is not None: - domain = self._provider_config.get_domain() + domain = self._login_widget.get_selected_provider() self._backend.soledad_bootstrap(username, domain, password) ################################################################### @@ -1457,19 +1473,8 @@ class MainWindow(QtGui.QMainWindow): # TODO in the OFFLINE mode we should also modify the rules # in the mail state machine so it shows that imap is active # (but not smtp since it's not yet ready for offline use) - start_fun = self._mail_conductor.start_imap_service - if flags.OFFLINE: - provider_domain = self._login_widget.get_selected_provider() - self._provider_config.load( - provider.get_provider_path(provider_domain)) - provides_mx = self._provider_config.provides_mx() - - if flags.OFFLINE and provides_mx: - start_fun() - return - - if self._provides_mx_and_enabled(): - start_fun() + if self._provides_mx_and_enabled() or flags.OFFLINE: + self._mail_conductor.start_imap_service() # end service control methods (imap) @@ -1519,9 +1524,7 @@ class MainWindow(QtGui.QMainWindow): """ self._eip_connection.qtsigs.connected_signal.emit() - provider_config = self._get_best_provider_config() - domain = provider_config.get_domain() - + domain = self._login_widget.get_selected_provider() self._eip_status.set_provider(domain) self._settings.set_defaultprovider(domain) self._already_started_eip = True @@ -1582,19 +1585,8 @@ class MainWindow(QtGui.QMainWindow): self._enabled_services = settings.get_enabled_services( default_provider) - loaded = self._provisional_provider_config.load( - provider.get_provider_path(default_provider)) - if loaded and settings.get_autostart_eip(): - # XXX I think we should not try to re-download config every time, - # it adds some delay. - # Maybe if it's the first run in a session, - # or we can try only if it fails. + if settings.get_autostart_eip(): self._maybe_start_eip() - elif settings.get_autostart_eip(): - # XXX: Display a proper message to the user - self.eip_needs_login.emit() - logger.error("Unable to load %s config, cannot autostart." % - (default_provider,)) @QtCore.Slot() def _start_EIP(self): @@ -1700,11 +1692,12 @@ class MainWindow(QtGui.QMainWindow): logger.debug('Setting autostart to: False') self._settings.set_autostart_eip(False) - if self._logged_user: - self._eip_status.set_provider( - make_address( - self._logged_user, - self._get_best_provider_config().get_domain())) + user = self._logged_user + if user: + domain = self._login_widget.get_selected_provider() + full_user_id = make_address(user, domain) + self._eip_status.set_provider(full_user_id) + self._eip_status.eip_stopped() @QtCore.Slot() @@ -1874,30 +1867,6 @@ class MainWindow(QtGui.QMainWindow): # end of EIP methods --------------------------------------------- - def _get_best_provider_config(self): - """ - Returns the best ProviderConfig to use at a moment. We may - have to use self._provider_config or - self._provisional_provider_config depending on the start - status. - - :rtype: ProviderConfig - """ - # TODO move this out of gui. - leap_assert(self._provider_config is not None or - self._provisional_provider_config is not None, - "We need a provider config") - - provider_config = None - if self._provider_config.loaded(): - provider_config = self._provider_config - elif self._provisional_provider_config.loaded(): - provider_config = self._provisional_provider_config - else: - leap_assert(False, "We could not find any usable ProviderConfig.") - - return provider_config - @QtCore.Slot() def _logout(self): """ diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 0a4c7f56..c67052f3 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -24,12 +24,9 @@ from functools import partial from PySide import QtCore, QtGui -from leap.bitmask.provider import get_provider_path from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.ui_preferences import Ui_Preferences from leap.bitmask.util.credentials import password_checks -from leap.bitmask.services import get_supported -from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.services import get_service_display_name, MX_SERVICE logger = logging.getLogger(__name__) @@ -41,15 +38,12 @@ class PreferencesWindow(QtGui.QDialog): """ preferences_saved = QtCore.Signal() - def __init__(self, parent, backend, provider_config, soledad_started, - username, domain): + def __init__(self, parent, backend, soledad_started, username, domain): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param backend: Backend being used :type backend: Backend - :param provider_config: ProviderConfig object. - :type provider_config: ProviderConfig :param soledad_started: whether soledad has started or not :type soledad_started: bool :param username: the user set in the login widget @@ -62,7 +56,6 @@ class PreferencesWindow(QtGui.QDialog): self._backend = backend self._settings = LeapSettings() - self._provider_config = provider_config self._soledad_started = soledad_started self._username = username self._domain = domain @@ -99,31 +92,7 @@ class PreferencesWindow(QtGui.QDialog): Actions to perform is the user is logged in. """ - settings = self._settings - pw_enabled = True - - # check if provider has 'mx' ... - # TODO: we should move this to the backend. - if self._provider_config.provides_mx(): - enabled_services = settings.get_enabled_services(self._domain) - mx_name = get_service_display_name(MX_SERVICE) - - # ... and if the user have it enabled - if MX_SERVICE not in enabled_services: - msg = self.tr("You need to enable {0} in order to change " - "the password.".format(mx_name)) - self._set_password_change_status(msg, error=True) - pw_enabled = False - else: - # check if Soledad is bootstrapped - if not self._soledad_started: - msg = self.tr( - "You need to wait until {0} is ready in " - "order to change the password.".format(mx_name)) - self._set_password_change_status(msg) - pw_enabled = False - - self.ui.gbPasswordChange.setEnabled(pw_enabled) + self._backend.provider_provides_mx() @QtCore.Slot() def _not_logged_in(self): @@ -138,6 +107,44 @@ class PreferencesWindow(QtGui.QDialog): self._set_password_change_status(msg) self.ui.gbPasswordChange.setEnabled(False) + @QtCore.Slot() + def _provides_mx(self): + """ + TRIGGERS: + Signaler.prov_provides_mx + + Actions to perform if the provider provides MX. + """ + pw_enabled = True + enabled_services = self._settings.get_enabled_services(self._domain) + mx_name = get_service_display_name(MX_SERVICE) + + if MX_SERVICE not in enabled_services: + msg = self.tr("You need to enable {0} in order to change " + "the password.".format(mx_name)) + self._set_password_change_status(msg, error=True) + pw_enabled = False + else: + # check if Soledad is bootstrapped + if not self._soledad_started: + msg = self.tr( + "You need to wait until {0} is ready in " + "order to change the password.".format(mx_name)) + self._set_password_change_status(msg) + pw_enabled = False + + self.ui.gbPasswordChange.setEnabled(pw_enabled) + + @QtCore.Slot() + def _not_provides_mx(self): + """ + TRIGGERS: + Signaler.prov_not_provides_mx + + Actions to perform if the provider does not provides MX. + """ + self.ui.gbPasswordChange.setEnabled(False) + @QtCore.Slot() def set_soledad_ready(self): """ @@ -339,8 +346,7 @@ class PreferencesWindow(QtGui.QDialog): TRIGGERS: self.ui.cbProvidersServices.currentIndexChanged[unicode] - Loads the services that the provider provides into the UI for - the user to enable or disable. + Fill the services list with the selected provider's services. :param domain: the domain of the provider to load services from. :type domain: str @@ -351,10 +357,6 @@ class PreferencesWindow(QtGui.QDialog): if not domain: return - provider_config = self._get_provider_config(domain) - if provider_config is None: - return - # set the proper connection for the 'save' button try: self.ui.pbSaveServices.clicked.disconnect() @@ -364,7 +366,21 @@ class PreferencesWindow(QtGui.QDialog): save_services = partial(self._save_enabled_services, domain) self.ui.pbSaveServices.clicked.connect(save_services) - services = get_supported(provider_config.get_services()) + self._backend.provider_get_supported_services(domain) + + @QtCore.Slot(str) + def _load_services(self, services): + """ + TRIGGERS: + self.ui.cbProvidersServices.currentIndexChanged[unicode] + + Loads the services that the provider provides into the UI for + the user to enable or disable. + + :param domain: the domain of the provider to load services from. + :type domain: str + """ + domain = self.ui.cbProvidersServices.currentText() services_conf = self._settings.get_enabled_services(domain) # discard changes if other provider is selected @@ -412,27 +428,15 @@ class PreferencesWindow(QtGui.QDialog): self._set_providers_services_status(msg, success=True) self.preferences_saved.emit() - def _get_provider_config(self, domain): - """ - Helper to return a valid Provider Config from the domain name. - - :param domain: the domain name of the provider. - :type domain: str - - :rtype: ProviderConfig or None if there is a problem loading the config - """ - provider_config = ProviderConfig() - if not provider_config.load(get_provider_path(domain)): - provider_config = None - - return provider_config - def _backend_connect(self): """ Helper to connect to backend signals """ sig = self._backend.signaler + sig.prov_provides_mx.connect(self._provides_mx) + sig.prov_get_supported_services.connect(self._load_services) + sig.srp_status_logged_in.connect(self._is_logged_in) sig.srp_status_not_logged_in.connect(self._not_logged_in) diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index ce45b431..4d774907 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -26,8 +26,6 @@ from PySide import QtCore, QtGui from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings -from leap.bitmask.config.providerconfig import ProviderConfig -from leap.bitmask.provider import get_provider_path from leap.bitmask.services import get_service_display_name, get_supported from leap.bitmask.util.credentials import password_checks, username_checks from leap.bitmask.util.credentials import USERNAME_REGEX @@ -88,10 +86,9 @@ class Wizard(QtGui.QWizard): self._backend_connect() self._domain = None - # HACK!! We need provider_config for the time being, it'll be - # removed - self._provider_config = ( - self._backend._components["provider"]._provider_config) + + # this details are set when the provider download is complete. + self._provider_details = None # We will store a reference to the defers for eventual use # (eg, to cancel them) but not doing anything with them right now. @@ -513,10 +510,12 @@ class Wizard(QtGui.QWizard): check. Since this check is the last of this set, it also completes the page if passed """ - if self._provider_config.load(get_provider_path(self._domain)): + if data[self._backend.PASSED_KEY]: self._complete_task(data, self.ui.lblProviderInfo, True, self.SELECT_PROVIDER_PAGE) self._provider_checks_ok = True + lang = QtCore.QLocale.system().name() + self._backend.provider_get_details(self._domain, lang) else: new_data = { self._backend.PASSED_KEY: False, @@ -538,6 +537,16 @@ class Wizard(QtGui.QWizard): else: self.ui.cbProviders.setEnabled(True) + @QtCore.Slot() + def _provider_get_details(self, details): + """ + Set the details for the just downloaded provider. + + :param details: the details of the provider. + :type details: ProviderConfigLight + """ + self._provider_details = details + @QtCore.Slot(dict) def _download_ca_cert(self, data): """ @@ -605,11 +614,9 @@ class Wizard(QtGui.QWizard): the user to enable or disable. """ self.ui.grpServices.setTitle( - self.tr("Services by %s") % - (self._provider_config.get_name(),)) + self.tr("Services by {0}").format(self._provider_details.name)) - services = get_supported( - self._provider_config.get_services()) + services = get_supported(self._provider_details.services) for service in services: try: @@ -652,38 +659,31 @@ class Wizard(QtGui.QWizard): if not self._provider_setup_ok: self._reset_provider_setup() sub_title = self.tr("Gathering configuration options for {0}") - sub_title = sub_title.format(self._provider_config.get_name()) + sub_title = sub_title.format(self._provider_details.name) self.page(pageId).setSubTitle(sub_title) self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) self._provider_setup_defer = self._backend.\ provider_bootstrap(self._domain) if pageId == self.PRESENT_PROVIDER_PAGE: - self.page(pageId).setSubTitle(self.tr("Description of services " - "offered by %s") % - (self._provider_config - .get_name(),)) - - lang = QtCore.QLocale.system().name() - self.ui.lblProviderName.setText( - "%s" % - (self._provider_config.get_name(lang=lang),)) - self.ui.lblProviderURL.setText( - "https://%s" % (self._provider_config.get_domain(),)) - self.ui.lblProviderDesc.setText( - "%s" % - (self._provider_config.get_description(lang=lang),)) - - self.ui.lblServicesOffered.setText(self._provider_config - .get_services_string()) - self.ui.lblProviderPolicy.setText(self._provider_config - .get_enrollment_policy()) + sub_title = self.tr("Description of services offered by {0}") + sub_title = sub_title.format(self._provider_details.name) + self.page(pageId).setSubTitle(sub_title) + + details = self._provider_details + name = "{0}".format(details.name) + domain = "https://{0}".format(details.domain) + description = "{0}".format(details.description) + self.ui.lblProviderName.setText(name) + self.ui.lblProviderURL.setText(domain) + self.ui.lblProviderDesc.setText(description) + self.ui.lblServicesOffered.setText(details.services_string) + self.ui.lblProviderPolicy.setText(details.enrollment_policy) if pageId == self.REGISTER_USER_PAGE: - self.page(pageId).setSubTitle(self.tr("Register a new user with " - "%s") % - (self._provider_config - .get_name(),)) + sub_title = self.tr("Register a new user with {0}") + sub_title = sub_title.format(self._provider_details.name) + self.page(pageId).setSubTitle(sub_title) self.ui.chkRemember.setVisible(False) if pageId == self.SERVICES_PAGE: @@ -706,8 +706,6 @@ class Wizard(QtGui.QWizard): if self.currentPage() == self.page(self.SELECT_PROVIDER_PAGE): if self._use_existing_provider: self._domain = self.ui.cbProviders.currentText() - self._provider_config = ProviderConfig.get_provider_config( - self._domain) if self._show_register: return self.REGISTER_USER_PAGE else: @@ -732,6 +730,7 @@ class Wizard(QtGui.QWizard): sig.prov_name_resolution.connect(self._name_resolution) sig.prov_https_connection.connect(self._https_connection) sig.prov_download_provider_info.connect(self._download_provider_info) + sig.prov_get_details.connect(self._provider_get_details) sig.prov_download_ca_cert.connect(self._download_ca_cert) sig.prov_check_ca_fingerprint.connect(self._check_ca_fingerprint) diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index 2bdad7e2..db12fd80 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -188,8 +188,9 @@ class SoledadBootstrapper(AbstractBootstrapper): try: self.load_and_sync_soledad(uuid, offline=True) self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FINISHED) - except Exception: + except Exception as e: # TODO: we should handle more specific exceptions in here + logger.exception(e) self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FAILED) def _get_soledad_local_params(self, uuid, offline=False): -- cgit v1.2.3