From 689c716b831047c8fe18945956e809b74e4250a3 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 1 Oct 2013 17:34:24 -0400 Subject: Disable EIP on/off button and action when login required. Also adds an explicit should_autostart flag in config. --- src/leap/bitmask/config/__init__.py | 0 src/leap/bitmask/config/leapsettings.py | 19 +++++ src/leap/bitmask/gui/eip_status.py | 26 +++++++ src/leap/bitmask/gui/login.py | 4 +- src/leap/bitmask/gui/mainwindow.py | 118 ++++++++++++++++++++--------- src/leap/bitmask/provider/__init__.py | 34 +++++++++ src/leap/bitmask/services/eip/eipconfig.py | 40 +++++++++- 7 files changed, 204 insertions(+), 37 deletions(-) delete mode 100644 src/leap/bitmask/config/__init__.py (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/config/__init__.py b/src/leap/bitmask/config/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/leap/bitmask/config/leapsettings.py b/src/leap/bitmask/config/leapsettings.py index 338fa475..dc1af899 100644 --- a/src/leap/bitmask/config/leapsettings.py +++ b/src/leap/bitmask/config/leapsettings.py @@ -65,6 +65,7 @@ class LeapSettings(object): PROPERPROVIDER_KEY = "ProperProvider" REMEMBER_KEY = "RememberUserAndPass" DEFAULTPROVIDER_KEY = "DefaultProvider" + AUTOSTARTEIP_KEY = "AutoStartEIP" ALERTMISSING_KEY = "AlertMissingScripts" GATEWAY_KEY = "Gateway" @@ -285,6 +286,24 @@ class LeapSettings(object): else: self._settings.setValue(self.DEFAULTPROVIDER_KEY, provider) + def get_autostart_eip(self): + """ + Gets whether the app should autostart EIP. + + :rtype: bool + """ + return to_bool(self._settings.value(self.AUTOSTARTEIP_KEY, False)) + + def set_autostart_eip(self, autostart): + """ + Sets whether the app should autostart EIP. + + :param autostart: True if we should try to autostart EIP. + :type autostart: bool + """ + leap_assert_type(autostart, bool) + self._settings.setValue(self.AUTOSTARTEIP_KEY, autostart) + def get_alert_missing_scripts(self): """ Returns the setting for alerting of missing up/down scripts. diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 6b1235a6..946eaa4e 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -233,6 +233,30 @@ class EIPStatusWidget(QtGui.QWidget): """ self.set_startstop_enabled(False) + @QtCore.Slot() + def disable_eip_start(self): + """ + Triggered when a default provider_config has not been found. + Disables the start button and adds instructions to the user. + """ + logger.debug('Hiding EIP start button') + # you might be tempted to change this for a .setEnabled(False). + # it won't work. it's under the claws of the state machine. + # probably the best thing would be to make a transitional + # transition there, but that's more involved. + self.eip_button.hide() + msg = self.tr("You must login to use Encrypted Internet") + self.eip_label.setText(msg) + + @QtCore.Slot() + def enable_eip_start(self): + """ + Triggered after a successful login. + Enables the start button. + """ + logger.debug('Showing EIP start button') + self.eip_button.show() + # XXX disable (later) -------------------------- def set_eip_status(self, status, error=False): """ @@ -261,6 +285,8 @@ class EIPStatusWidget(QtGui.QWidget): :param value: True for enabled, False otherwise :type value: bool """ + # TODO use disable_eip_start instead + # this should be handled by the state machine leap_assert_type(value, bool) self.ui.btnEipStartStop.setEnabled(value) self._action_eip_startstop.setEnabled(value) diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index c635081c..582f26be 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -14,7 +14,6 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - """ Login widget implementation """ @@ -36,9 +35,9 @@ class LoginWidget(QtGui.QWidget): Login widget that emits signals to display the wizard or to perform login. """ - # Emitted when the login button is clicked login = QtCore.Signal() + logged_in_signal = QtCore.Signal() cancel_login = QtCore.Signal() logout = QtCore.Signal() @@ -320,6 +319,7 @@ class LoginWidget(QtGui.QWidget): self.ui.lblUser.setText("%s@%s" % (self.get_user(), self.get_selected_provider())) self.set_login_status("") + self.logged_in_signal.emit() def logged_out(self): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 58ed3eb3..7129b670 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -38,9 +38,10 @@ from leap.bitmask.gui.eip_status import EIPStatusWidget from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.wizard import Wizard +from leap.bitmask import provider from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper -from leap.bitmask.services.eip.eipconfig import EIPConfig +from leap.bitmask.services.eip import eipconfig # XXX: Soledad might not work out of the box in Windows, issue #2932 from leap.bitmask.services.soledad.soledadbootstrapper import \ SoledadBootstrapper @@ -100,6 +101,7 @@ class MainWindow(QtGui.QMainWindow): MX_SERVICE = "mx" # Signals + eip_needs_login = QtCore.Signal([]) new_updates = QtCore.Signal(object) raise_window = QtCore.Signal([]) soledad_ready = QtCore.Signal([]) @@ -162,6 +164,10 @@ class MainWindow(QtGui.QMainWindow): self._eip_status = EIPStatusWidget(self) self.ui.eipLayout.addWidget(self._eip_status) + self._login_widget.logged_in_signal.connect( + self._eip_status.enable_eip_start) + self._login_widget.logged_in_signal.connect( + self._enable_eip_start_action) self._mail_status = MailStatusWidget(self) self.ui.mailLayout.addWidget(self._mail_status) @@ -174,13 +180,17 @@ class MainWindow(QtGui.QMainWindow): self._stop_eip) self._eip_status.eip_connection_connected.connect( self._on_eip_connected) + self.eip_needs_login.connect( + self._eip_status.disable_eip_start) + self.eip_needs_login.connect( + self._disable_eip_start_action) # This is loaded only once, there's a bug when doing that more # than once self._provider_config = ProviderConfig() # Used for automatic start of EIP self._provisional_provider_config = ProviderConfig() - self._eip_config = EIPConfig() + self._eip_config = eipconfig.EIPConfig() self._already_started_eip = False @@ -309,27 +319,29 @@ class MainWindow(QtGui.QMainWindow): self._smtp_config = SMTPConfig() - if self._first_run(): - self._wizard_firstrun = True - self._wizard = Wizard(bypass_checks=bypass_checks) - # Give this window time to finish init and then show the wizard - QtCore.QTimer.singleShot(1, self._launch_wizard) - self._wizard.accepted.connect(self._finish_init) - self._wizard.rejected.connect(self._rejected_wizard) - else: - self._finish_init() - # Eip machine is a public attribute where the state machine for # the eip connection will be available to the different components. # Remember that this will not live in the +1600LOC mainwindow for # all the eternity, so at some point we will be moving this to # the EIPConductor or some other clever component that we will # instantiate from here. - self.eip_machine = None + self.eip_machine = None # start event machines self.start_eip_machine() + if self._first_run(): + self._wizard_firstrun = True + self._wizard = Wizard(bypass_checks=bypass_checks) + # Give this window time to finish init and then show the wizard + QtCore.QTimer.singleShot(1, self._launch_wizard) + self._wizard.accepted.connect(self._finish_init) + self._wizard.rejected.connect(self._rejected_wizard) + else: + # during finish_init, we disable the eip start button + # so this has to be done after eip_machine is started + self._finish_init() + def _rejected_wizard(self): """ SLOT @@ -582,21 +594,29 @@ class MainWindow(QtGui.QMainWindow): """ Tries to autostart EIP """ - default_provider = self._settings.get_defaultprovider() + settings = self._settings + + should_autostart = settings.get_autostart_eip() + if not should_autostart: + logger.debug('Will not autostart EIP since it is setup ' + 'to not to do it') + self.eip_needs_login.emit() + return + + default_provider = settings.get_defaultprovider() if default_provider is None: logger.info("Cannot autostart Encrypted Internet because there is " "no default provider configured") + self.eip_needs_login.emit() return - self._enabled_services = self._settings.get_enabled_services( + self._enabled_services = settings.get_enabled_services( default_provider) - if self._provisional_provider_config.load( - os.path.join("leap", - "providers", - default_provider, - "provider.json")): + loaded = self._provisional_provider_config.load( + provider.get_provider_path(default_provider)) + if loaded: # 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, @@ -604,6 +624,7 @@ class MainWindow(QtGui.QMainWindow): self._download_eip_config() else: # XXX: Display a proper message to the user + self.eip_needs_login.emit() logger.error("Unable to load %s config, cannot autostart." % (default_provider,)) @@ -1165,6 +1186,21 @@ class MainWindow(QtGui.QMainWindow): label=label) self.eip_machine = eip_machine self.eip_machine.start() + logger.debug('eip machine started') + + @QtCore.Slot() + def _disable_eip_start_action(self): + """ + Disables the EIP start action in the systray menu. + """ + self._action_eip_startstop.setEnabled(False) + + @QtCore.Slot() + def _enable_eip_start_action(self): + """ + Enables the EIP start action in the systray menu. + """ + self._action_eip_startstop.setEnabled(True) @QtCore.Slot() def _on_eip_connected(self): @@ -1197,6 +1233,27 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.eip_pre_up() self.user_stopped_eip = False + # until we set an option in the preferences window, + # we'll assume that by default we try to autostart. + # If we switch it off manually, it won't try the next + # time. + self._settings.set_autostart_eip(True) + + loaded = eipconfig.load_eipconfig_if_needed( + provider_config, self._eip_config, provider) + + if not loaded: + self._eip_status.set_eip_status( + self.tr("Could not load Encrypted Internet " + "Configuration."), + error=True) + # signal connection aborted to state machine + qtsigs = self._eip_connection.qtsigs + qtsigs.connection_aborted_signal.emit() + logger.error("Tried to start EIP but cannot find any " + "available provider!") + return + try: # XXX move this to EIPConductor host, port = get_openvpn_management() @@ -1263,7 +1320,7 @@ class MainWindow(QtGui.QMainWindow): self._already_started_eip = True @QtCore.Slot() - def _stop_eip(self, abnormal=False): + def _stop_eip(self): """ SLOT TRIGGERS: @@ -1277,18 +1334,15 @@ class MainWindow(QtGui.QMainWindow): :param abnormal: whether this was an abnormal termination. :type abnormal: bool """ - if abnormal: - logger.warning("Abnormal EIP termination.") - self.user_stopped_eip = True self._vpn.terminate() self._set_eipstatus_off(False) - self._already_started_eip = False - # XXX do via signal - self._settings.set_defaultprovider(None) + logger.debug('Setting autostart to: False') + self._settings.set_autostart_eip(False) + if self._logged_user: self._eip_status.set_provider( "%s@%s" % (self._logged_user, @@ -1351,13 +1405,9 @@ class MainWindow(QtGui.QMainWindow): provider_config = self._get_best_provider_config() domain = provider_config.get_domain() - loaded = self._eip_config.loaded() - if not loaded: - eip_config_path = os.path.join("leap", "providers", - domain, "eip-service.json") - api_version = provider_config.get_api_version() - self._eip_config.set_api_version(api_version) - loaded = self._eip_config.load(eip_config_path) + # XXX move check to _start_eip ? + loaded = eipconfig.load_eipconfig_if_needed( + provider_config, self._eip_config, domain) if loaded: # DO START EIP Connection! diff --git a/src/leap/bitmask/provider/__init__.py b/src/leap/bitmask/provider/__init__.py index e69de29b..53587d65 100644 --- a/src/leap/bitmask/provider/__init__.py +++ b/src/leap/bitmask/provider/__init__.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# __init.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Module initialization for leap.bitmask.provider +""" +import os +from leap.common.check import leap_assert + + +def get_provider_path(domain): + """ + Returns relative path for provider config. + + :param domain: the domain to which this providerconfig belongs to. + :type domain: str + :returns: the path + :rtype: str + """ + leap_assert(domain is not None, "get_provider_path: We need a domain") + return os.path.join("leap", "providers", domain, "provider.json") diff --git a/src/leap/bitmask/services/eip/eipconfig.py b/src/leap/bitmask/services/eip/eipconfig.py index 7d8995b4..16ed4cc0 100644 --- a/src/leap/bitmask/services/eip/eipconfig.py +++ b/src/leap/bitmask/services/eip/eipconfig.py @@ -33,6 +33,45 @@ from leap.common.check import leap_assert, leap_assert_type logger = logging.getLogger(__name__) +def get_eipconfig_path(domain): + """ + Returns relative path for EIP config. + + :param domain: the domain to which this eipconfig belongs to. + :type domain: str + :returns: the path + :rtype: str + """ + leap_assert(domain is not None, "get_eipconfig_path: We need a domain") + return os.path.join("leap", "providers", domain, "eip-service.json") + + +def load_eipconfig_if_needed(provider_config, eip_config, domain): + """ + Utility function to prime a eip_config object from a loaded + provider_config and the chosen provider domain. + + :param provider_config: a loaded instance of ProviderConfig + :type provider_config: ProviderConfig + + :param eip_config: the eipconfig object to be primed. + :type eip_config: EIPConfig + + :param domain: the chosen provider domain + :type domain: str + + :returns: Whether the eip_config object has been succesfully loaded + :rtype: bool + """ + loaded = eip_config.loaded() + if not loaded: + eip_config_path = get_eipconfig_path(domain) + api_version = provider_config.get_api_version() + eip_config.set_api_version(api_version) + loaded = eip_config.load(eip_config_path) + return loaded + + class VPNGatewaySelector(object): """ VPN Gateway selector. @@ -59,7 +98,6 @@ class VPNGatewaySelector(object): tz_offset = self.equivalent_timezones[tz_offset] self._local_offset = tz_offset - self._eipconfig = eipconfig def get_gateways_list(self): -- cgit v1.2.3