From 8cce83844448a83ab03cb8a3a04320547e024d06 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 27 Aug 2013 09:52:53 -0300 Subject: Move configured providers getter to LeapSettings. --- src/leap/bitmask/config/leapsettings.py | 29 ++++++++++++++++++++++++----- src/leap/bitmask/gui/mainwindow.py | 27 ++++----------------------- 2 files changed, 28 insertions(+), 28 deletions(-) (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/config/leapsettings.py b/src/leap/bitmask/config/leapsettings.py index 35010280..6aab84e4 100644 --- a/src/leap/bitmask/config/leapsettings.py +++ b/src/leap/bitmask/config/leapsettings.py @@ -75,11 +75,10 @@ class LeapSettings(object): the config :type standalone: bool """ - - settings_path = os.path.join(get_platform_prefixer() - .get_path_prefix(standalone=standalone), - "leap", - self.CONFIG_NAME) + self._path_prefix = get_platform_prefixer().get_path_prefix( + standalone=standalone) + settings_path = os.path.join( + self._path_prefix, "leap", self.CONFIG_NAME) self._settings = QtCore.QSettings(settings_path, QtCore.QSettings.IniFormat) @@ -119,6 +118,26 @@ class LeapSettings(object): leap_assert(windowstate, "We need a window state") self._settings.setValue(self.WINDOWSTATE_KEY, windowstate) + def get_configured_providers(self): + """ + Returns the configured providers based on the file structure in the + settings directory. + + :rtype: list of str + """ + # TODO: check which providers have a valid certificate among + # other things, not just the directories + providers = [] + try: + providers_path = os.path.join( + self._path_prefix, "leap", "providers") + providers = os.listdir(providers_path) + except Exception as e: + logger.debug("Error listing providers, assume there are none. %r" + % (e,)) + + return providers + def get_enabled_services(self, provider): """ Returns a list of enabled services for the given provider diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index c832887a..7b9d492e 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -491,7 +491,8 @@ class MainWindow(QtGui.QMainWindow): """ # XXX: May be this can be divided into two methods? - self._login_widget.set_providers(self._configured_providers()) + providers = self._settings.get_configured_providers() + self._login_widget.set_providers(providers) self._show_systray() self.show() if IS_MAC: @@ -736,34 +737,14 @@ class MainWindow(QtGui.QMainWindow): QtGui.QMainWindow.closeEvent(self, e) - def _configured_providers(self): - """ - Returns the available providers based on the file structure - - :rtype: list - """ - - # TODO: check which providers have a valid certificate among - # other things, not just the directories - providers = [] - try: - providers = os.listdir( - os.path.join(self._provider_config.get_path_prefix(), - "leap", - "providers")) - except Exception as e: - logger.debug("Error listing providers, assume there are none. %r" - % (e,)) - - return providers - def _first_run(self): """ Returns True if there are no configured providers. False otherwise :rtype: bool """ - has_provider_on_disk = len(self._configured_providers()) != 0 + providers = self._settings.get_configured_providers() + has_provider_on_disk = len(providers) != 0 is_proper_provider = self._settings.get_properprovider() return not (has_provider_on_disk and is_proper_provider) -- cgit v1.2.3 From 956330af5a67922e7710e7c4817de8fc15fab5ac Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 27 Aug 2013 11:05:00 -0300 Subject: Remove key for a provider with no enabled services --- src/leap/bitmask/config/leapsettings.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/config/leapsettings.py b/src/leap/bitmask/config/leapsettings.py index 6aab84e4..c1fabd9c 100644 --- a/src/leap/bitmask/config/leapsettings.py +++ b/src/leap/bitmask/config/leapsettings.py @@ -170,8 +170,12 @@ class LeapSettings(object): leap_assert(len(provider) > 0, "We need a nonempty provider") leap_assert_type(services, list) - self._settings.setValue("%s/Services" % (provider,), - services) + key = "{0}/Services".format(provider) + if not services: + # if there are no enabled services we don't need that key + self._settings.remove(key) + else: + self._settings.setValue(key, services) def get_user(self): """ -- cgit v1.2.3 From 45796e0256e3a57e506d6db8c2bde62a510ae6ae Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 26 Aug 2013 17:47:01 -0300 Subject: Preferences: select enabled services for providers --- src/leap/bitmask/gui/mainwindow.py | 11 +- src/leap/bitmask/gui/preferenceswindow.py | 165 +++++++++++++++++++++++++++++- src/leap/bitmask/gui/ui/mainwindow.ui | 2 +- src/leap/bitmask/gui/ui/preferences.ui | 78 ++++++++++++-- 4 files changed, 236 insertions(+), 20 deletions(-) (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 7b9d492e..34451928 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -288,17 +288,12 @@ class MainWindow(QtGui.QMainWindow): ################################# end Qt Signals connection ######## - # Enable the password change when soledad is ready - self.soledad_ready.connect( - partial(self.ui.btnPreferences.setEnabled, True)) - init_platform() self._wizard = None self._wizard_firstrun = False self._logger_window = None - self._preferences_window = None self._bypass_checks = bypass_checks @@ -419,7 +414,11 @@ class MainWindow(QtGui.QMainWindow): Displays the preferences window. """ - PreferencesWindow(self, self._srp_auth, self._soledad).show() + preferences_window = PreferencesWindow( + self, self._srp_auth, self._soledad, + self._settings, self._standalone) + + preferences_window.show() def _uncheck_logger_button(self): """ diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index a8220e86..f580e703 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -18,15 +18,18 @@ """ Preferences window """ +import os import logging from functools import partial -from PySide import QtGui +from PySide import QtCore, QtGui from leap.bitmask.gui.ui_preferences import Ui_Preferences from leap.soledad.client import NoStorageSecret from leap.bitmask.crypto.srpauth import SRPAuthBadPassword from leap.bitmask.util.password import basic_password_checks +from leap.bitmask.services import get_supported +from leap.bitmask.config.providerconfig import ProviderConfig logger = logging.getLogger(__name__) @@ -38,7 +41,7 @@ class PreferencesWindow(QtGui.QDialog): WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password") - def __init__(self, parent, srp_auth, soledad): + def __init__(self, parent, srp_auth, soledad, leap_settings): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -51,14 +54,51 @@ class PreferencesWindow(QtGui.QDialog): self._srp_auth = srp_auth self._soledad = soledad + self._settings = leap_settings # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) + self.ui.lblProvidersServicesStatus.setVisible(False) + + # Correspondence for services and their name to display + EIP_LABEL = self.tr("Encrypted Internet") + MX_LABEL = self.tr("Encrypted Mail") + + self.SERVICE_DISPLAY = [ + EIP_LABEL, + MX_LABEL + ] + self.SERVICE_CONFIG = [ + "openvpn", + "mx" + ] + + self._selected_services = set() + self._provider_config = ProviderConfig() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) + self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( + self._populate_services) + + parent.soledad_ready.connect(self._soledad_ready) + + if not self._settings.get_configured_providers(): + self.ui.gbEnabledServices.setEnabled(False) + else: + self._add_configured_providers() + + def _soledad_ready(self): + """ + SLOT + TRIGGERS: + parent.soledad_ready + It sets the soledad object as ready to use. + """ + self._soledad_ready = True + self.ui.gbPasswordChange.setEnabled(True) def _set_password_change_status(self, status, error=False, success=False): """ @@ -134,7 +174,7 @@ class PreferencesWindow(QtGui.QDialog): self._set_password_change_status( self.tr("Password changed successfully."), success=True) - self._clear_inputs() + self._clear_password_inputs() self._set_changing_password(False) def _change_password_problem(self, failure): @@ -156,10 +196,127 @@ class PreferencesWindow(QtGui.QDialog): self._set_changing_password(False) failure.trap(Exception) - def _clear_inputs(self): + def _clear_password_inputs(self): """ Clear the contents of the inputs. """ self.ui.leCurrentPassword.setText("") self.ui.leNewPassword.setText("") self.ui.leNewPassword2.setText("") + + def _set_providers_services_status(self, status, success=False): + """ + Sets the status label for the password change. + + :param status: status message to display, can be HTML + :type status: str + """ + if success: + status = "%s" % (status,) + + self.ui.lblProvidersServicesStatus.setVisible(True) + self.ui.lblProvidersServicesStatus.setText(status) + + def _add_configured_providers(self): + """ + Add the client's configured providers to the providers combo boxes. + """ + self.ui.cbProvidersServices.clear() + self.ui.cbProvidersGateway.clear() + for provider in self._settings.get_configured_providers(): + self.ui.cbProvidersServices.addItem(provider) + self.ui.cbProvidersGateway.addItem(provider) + + def _service_selection_changed(self, service, state): + """ + SLOT + TRIGGER: service_checkbox.stateChanged + Adds the service to the state if the state is checked, removes + it otherwise + + :param service: service to handle + :type service: str + :param state: state of the checkbox + :type state: int + """ + if state == QtCore.Qt.Checked: + self._selected_services = \ + self._selected_services.union(set([service])) + else: + self._selected_services = \ + self._selected_services.difference(set([service])) + + # We hide the maybe-visible status label after a change + self.ui.lblProvidersServicesStatus.setVisible(False) + + def _populate_services(self, domain): + """ + SLOT + TRIGGERS: + self.ui.cbProvidersServices.clicked + + 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 + """ + # We hide the maybe-visible status label after a change + self.ui.lblProvidersServicesStatus.setVisible(False) + + provider_config_path = os.path.join( + "leap", "providers", domain, "provider.json") + + if not domain or not self._provider_config.load(provider_config_path): + return + + # set the proper connection for the 'save' button + try: + self.ui.pbSaveServices.clicked.disconnect() + except RuntimeError: + pass # Signal was not connected + + save_services = partial(self._save_enabled_services, domain) + self.ui.pbSaveServices.clicked.connect(save_services) + + services = get_supported(self._provider_config.get_services()) + services_conf = self._settings.get_enabled_services(domain) + + # discard changes if other provider is selected + self._selected_services = set() + + # from: http://stackoverflow.com/a/13103617/687989 + # remove existing checkboxes + layout = self.ui.vlServices + for i in reversed(range(layout.count())): + layout.itemAt(i).widget().setParent(None) + + # add one checkbox per service and set the current configured value + for service in services: + try: + checkbox = QtGui.QCheckBox(self) + service_index = self.SERVICE_CONFIG.index(service) + checkbox.setText(self.SERVICE_DISPLAY[service_index]) + self.ui.vlServices.addWidget(checkbox) + checkbox.stateChanged.connect( + partial(self._service_selection_changed, service)) + + checkbox.setChecked(service in services_conf) + except ValueError: + logger.error("Something went wrong while trying to " + "load service %s" % (service,)) + + def _save_enabled_services(self, provider): + """ + Saves the new settings to the configuration file. + + :param provider: the provider config that we need to save. + :type provider: str + """ + services = list(self._selected_services) + self._settings.set_enabled_services(provider, services) + + msg = self.tr( + "Services settings for provider '{0}' saved.".format(provider)) + logger.debug(msg) + self._set_providers_services_status(msg, success=True) diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 834a562e..17837642 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -217,7 +217,7 @@ - false + true Preferences diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index 8c63ccad..b59990b1 100644 --- a/src/leap/bitmask/gui/ui/preferences.ui +++ b/src/leap/bitmask/gui/ui/preferences.ui @@ -6,8 +6,8 @@ 0 0 - 451 - 267 + 453 + 463 @@ -17,9 +17,12 @@ :/images/mask-icon.png:/images/mask-icon.png - - + + + + false + Password Change @@ -98,7 +101,64 @@ - + + + + Enabled services + + + + + + Save this provider settings + + + + + + + Services + + + false + + + + + + + + + + + + + <Select provider> + + + + + + + + Select provider: + + + + + + + < Providers Services Status > + + + Qt::AlignCenter + + + + + + + false @@ -116,12 +176,12 @@ &Select provider: - cbProviders + cbProvidersGateway - + <Select provider> @@ -137,7 +197,7 @@ - + Automatic @@ -148,7 +208,7 @@ - + Qt::Vertical -- cgit v1.2.3 From 39395c6c9ac3bc7011f5ac3fbe5da9605f36ed18 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 27 Aug 2013 17:52:40 -0300 Subject: Refactor services display names out. Closes #3578. --- src/leap/bitmask/gui/preferenceswindow.py | 27 ++++++++++-------------- src/leap/bitmask/gui/wizard.py | 25 +++++----------------- src/leap/bitmask/services/__init__.py | 35 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 36 deletions(-) (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index f580e703..05f616b0 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -30,6 +30,7 @@ from leap.bitmask.crypto.srpauth import SRPAuthBadPassword from leap.bitmask.util.password import basic_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 logger = logging.getLogger(__name__) @@ -41,7 +42,7 @@ class PreferencesWindow(QtGui.QDialog): WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password") - def __init__(self, parent, srp_auth, soledad, leap_settings): + def __init__(self, parent, srp_auth, soledad, leap_settings, standalone): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -49,12 +50,17 @@ class PreferencesWindow(QtGui.QDialog): :type srp_auth: SRPAuth :param soledad: Soledad object configured in the main app. :type soledad: Soledad + :param standalone: If True, the application is running as standalone + and the preferences dialog should display some + messages according to this. + :type standalone: bool """ QtGui.QDialog.__init__(self, parent) self._srp_auth = srp_auth self._soledad = soledad self._settings = leap_settings + self._standalone = standalone # Load UI self.ui = Ui_Preferences() @@ -62,19 +68,6 @@ class PreferencesWindow(QtGui.QDialog): self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) - # Correspondence for services and their name to display - EIP_LABEL = self.tr("Encrypted Internet") - MX_LABEL = self.tr("Encrypted Mail") - - self.SERVICE_DISPLAY = [ - EIP_LABEL, - MX_LABEL - ] - self.SERVICE_CONFIG = [ - "openvpn", - "mx" - ] - self._selected_services = set() self._provider_config = ProviderConfig() @@ -295,8 +288,10 @@ class PreferencesWindow(QtGui.QDialog): for service in services: try: checkbox = QtGui.QCheckBox(self) - service_index = self.SERVICE_CONFIG.index(service) - checkbox.setText(self.SERVICE_DISPLAY[service_index]) + service_label = get_service_display_name( + service, self._standalone) + checkbox.setText(service_label) + self.ui.vlServices.addWidget(checkbox) checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index e3f0085b..ac0f032f 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -34,7 +34,7 @@ from leap.bitmask.util.request_helpers import get_content from leap.bitmask.util.keyring_helpers import has_keyring from leap.bitmask.util.password import basic_password_checks from leap.bitmask.services.eip.providerbootstrapper import ProviderBootstrapper -from leap.bitmask.services import get_supported +from leap.bitmask.services import get_service_display_name, get_supported from ui_wizard import Ui_Wizard @@ -84,23 +84,6 @@ class Wizard(QtGui.QWizard): self.ERROR_ICON = QtGui.QPixmap(":/images/Dialog-error.png") self.OK_ICON = QtGui.QPixmap(":/images/Dialog-accept.png") - # Correspondence for services and their name to display - EIP_LABEL = self.tr("Encrypted Internet") - MX_LABEL = self.tr("Encrypted Mail") - - if self._is_need_eip_password_warning(): - EIP_LABEL += " " + self.tr( - "(will need admin password to start)") - - self.SERVICE_DISPLAY = [ - EIP_LABEL, - MX_LABEL - ] - self.SERVICE_CONFIG = [ - "openvpn", - "mx" - ] - self._selected_services = set() self._shown_services = set() @@ -507,8 +490,10 @@ class Wizard(QtGui.QWizard): try: if service not in self._shown_services: checkbox = QtGui.QCheckBox(self) - service_index = self.SERVICE_CONFIG.index(service) - checkbox.setText(self.SERVICE_DISPLAY[service_index]) + service_label = get_service_display_name( + service, self.standalone) + checkbox.setText(service_label) + self.ui.serviceListLayout.addWidget(checkbox) checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) diff --git a/src/leap/bitmask/services/__init__.py b/src/leap/bitmask/services/__init__.py index 253359cd..924ca547 100644 --- a/src/leap/bitmask/services/__init__.py +++ b/src/leap/bitmask/services/__init__.py @@ -17,9 +17,44 @@ """ Services module. """ +from PySide import QtCore +from leap.bitmask.util.privilege_policies import is_missing_policy_permissions + DEPLOYED = ["openvpn", "mx"] +def get_service_display_name(service, standalone=False): + """ + Returns the name to display of the given service. + + :param service: the 'machine' service name + :type service: str + :param standalone: True if the app is running in a standalone mode, used + to display messages according that. + :type standalone: bool + + :rtype: str + """ + # qt translator method helper + _tr = QtCore.QObject().tr + + # Correspondence for services and their name to display + EIP_LABEL = _tr("Encrypted Internet") + MX_LABEL = _tr("Encrypted Mail") + + service_display = [EIP_LABEL, MX_LABEL] + service_config = ["openvpn", "mx"] + + # If we need to add a warning about eip needing + # administrative permissions to start. That can be either + # because we are running in standalone mode, or because we could + # not find the needed privilege escalation mechanisms being operative. + if standalone or is_missing_policy_permissions(): + EIP_LABEL += " " + _tr("(will need admin password to start)") + + return service_display[service_config.index(service)] + + def get_supported(services): """ Returns a list of the available services. -- cgit v1.2.3