diff options
25 files changed, 291 insertions, 187 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e8d24c95..c47e531a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,36 @@ History 2014 ==== +0.6.1 August 15 -- the "knock knock knocking on beta's door" release: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +- Add checks to ensure that the backend is alive or notify the + user. Related to #5873. +- Stop the backend if the frontend process does not exist any more and + backend is not a daemon. Related to #5873. +- Add autostart on Linux. Closes #4989. +- Pressing ESC on 'install helper files' defaults to No. Closes #5819. +- Replace twisted thread with QThread and get pastebin send + working. Closes #5949. +- Wait until EIP is up to autologin. Closes #5939 +- Fix the handling of vpn launcher errors in the UI. Closes: #5955 +- Fix logger window blocking the bitmask quit(). +- Set the standalone value for BaseConfig according to the global + flags. +- Improve Hide and Show Window behavior on Ubuntu. Fixes #5511. +- Use smaller height on the window so it fits better on smaller + resolutions. Closes #5722. +- Disable daemon mode when we run the backend so we can spawn child + processes on it. +- Restrict access to the zmq certificates folder. +- Stop the services if the selected provider is changed. Related to + #4704. Closes #5912, #5554. +- Minor adjustments to the layout of UI elements. Fixes #5514, #5515, + #5510. +- Moved provider selection dropdown menu to be at the top of the main + windowUse same user/password restrictions as in the webapp. Closes + #5894. + 0.6.0 July 18 -- the "nothing to see here" release: +++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/changes/4035_add-eip-cancel-button b/changes/4035_add-eip-cancel-button deleted file mode 100644 index ea63f8a4..00000000 --- a/changes/4035_add-eip-cancel-button +++ /dev/null @@ -1 +0,0 @@ -- Add a button for cancelling ongoing EIP connection. Closes: #4035 diff --git a/changes/5870_bitmask-prevent-system-logout-on-linux b/changes/5870_bitmask-prevent-system-logout-on-linux deleted file mode 100644 index 6feba46c..00000000 --- a/changes/5870_bitmask-prevent-system-logout-on-linux +++ /dev/null @@ -1 +0,0 @@ -- Bitmask on linux prevents session logout. Closes #5870. diff --git a/changes/add-backend-alive-check b/changes/add-backend-alive-check deleted file mode 100644 index 40e12978..00000000 --- a/changes/add-backend-alive-check +++ /dev/null @@ -1 +0,0 @@ -- Add checks to ensure that the backend is alive or notify the user. Related to #5873. diff --git a/changes/add-frontend-alive-check b/changes/add-frontend-alive-check deleted file mode 100644 index 54f88798..00000000 --- a/changes/add-frontend-alive-check +++ /dev/null @@ -1,2 +0,0 @@ -- Stop the backend if the frontend process does not exist any more and backend - is not a daemon. Related to #5873. diff --git a/changes/add-linux-autostart b/changes/add-linux-autostart deleted file mode 100644 index 44b175bc..00000000 --- a/changes/add-linux-autostart +++ /dev/null @@ -1 +0,0 @@ -- Add autostart on Linux. Closes #4989. diff --git a/changes/bug-5949_pastebin-does-not-work b/changes/bug-5949_pastebin-does-not-work deleted file mode 100644 index aa983184..00000000 --- a/changes/bug-5949_pastebin-does-not-work +++ /dev/null @@ -1 +0,0 @@ -- Replace twisted thread with QThread and get pastebin send working. Closes #5949. diff --git a/changes/bug_5939_wait-for-eip-to-autologin b/changes/bug_5939_wait-for-eip-to-autologin deleted file mode 100644 index 5dec8331..00000000 --- a/changes/bug_5939_wait-for-eip-to-autologin +++ /dev/null @@ -1 +0,0 @@ -- Wait until EIP is up to autologin. Closes #5939 diff --git a/changes/bug_5955_fix-vpnlauncher-error-ui b/changes/bug_5955_fix-vpnlauncher-error-ui deleted file mode 100644 index d322288e..00000000 --- a/changes/bug_5955_fix-vpnlauncher-error-ui +++ /dev/null @@ -1 +0,0 @@ -- Fix the handling of vpn launcher errors in the UI. Closes: #5955 diff --git a/changes/bug_logger-hangs-quit b/changes/bug_logger-hangs-quit deleted file mode 100644 index b76f6218..00000000 --- a/changes/bug_logger-hangs-quit +++ /dev/null @@ -1 +0,0 @@ -- Fix logger window blocking the bitmask quit(). diff --git a/changes/bug_set-standalone-flags-for-baseconfig b/changes/bug_set-standalone-flags-for-baseconfig deleted file mode 100644 index bf84d3e8..00000000 --- a/changes/bug_set-standalone-flags-for-baseconfig +++ /dev/null @@ -1 +0,0 @@ -- Set the standalone value for BaseConfig according to the global flags. diff --git a/changes/bug_show_hide_improved b/changes/bug_show_hide_improved deleted file mode 100644 index 39472074..00000000 --- a/changes/bug_show_hide_improved +++ /dev/null @@ -1 +0,0 @@ -- Improve Hide and Show Window behavior on Ubuntu. Fixes #5511.
\ No newline at end of file diff --git a/changes/bug_use-smaller-window-to-fit-lower-resolutions b/changes/bug_use-smaller-window-to-fit-lower-resolutions deleted file mode 100644 index d9df69ae..00000000 --- a/changes/bug_use-smaller-window-to-fit-lower-resolutions +++ /dev/null @@ -1 +0,0 @@ -- Use smaller height on the window so it fits better on smaller resolutions. Closes #5722. diff --git a/changes/disable-user-pass-remembering b/changes/disable-user-pass-remembering deleted file mode 100644 index 45411001..00000000 --- a/changes/disable-user-pass-remembering +++ /dev/null @@ -1 +0,0 @@ -- Temporarily disable username/password remembering to avoid keyring issues. Related to #4190. diff --git a/changes/enable-child-process-in-backend b/changes/enable-child-process-in-backend deleted file mode 100644 index 1b6f246e..00000000 --- a/changes/enable-child-process-in-backend +++ /dev/null @@ -1 +0,0 @@ -- Disable daemon mode when we run the backend so we can spawn child processes on it. diff --git a/changes/feature_restrict-certificates-permissions b/changes/feature_restrict-certificates-permissions deleted file mode 100644 index 6bd6c015..00000000 --- a/changes/feature_restrict-certificates-permissions +++ /dev/null @@ -1 +0,0 @@ -- Restrict access to the zmq certificates folder. diff --git a/changes/minor-ui-adjustments b/changes/minor-ui-adjustments deleted file mode 100644 index 33e27964..00000000 --- a/changes/minor-ui-adjustments +++ /dev/null @@ -1 +0,0 @@ -- minor adjustments to the layout of UI elements (#5514, #5515, #5510). diff --git a/relnotes.txt b/relnotes.txt index 925db87d..183d1f86 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -1,8 +1,8 @@ -ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.6.0 +ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.6.1 The LEAP team is pleased to announce the immediate availability of -version 0.6.0 of Bitmask, the Internet Encryption Toolkit, codename -"nothing to see here". +version 0.6.1 of Bitmask, the Internet Encryption Toolkit, codename +"knock knock knocking on beta's door". https://downloads.leap.se/client/ @@ -43,11 +43,13 @@ NOT trust your life to it. WHAT CAN THIS VERSION OF BITMASK DO FOR ME? -Bitmask 0.6.0 improves how email encryption/decryption works -internally to improve speed and CPU consumption. This release also -merges a big refactor we've been working on for some time, which will -give us room for a lot of improvements in the near future. You can -refer to the CHANGELOG for the meat. +Bitmask 0.6.1 is the new stable version of the client after the big +refactor, with a little face lift of the UI while we were at +it. Encrypted Email is still not stable though, so don't use it for +high security. Encrypted Internet is the first service we are calling +stable, although its security level is just a bit higher than plain +OpenSSL, so use accordingly. You can refer to the CHANGELOG for the +meat. Encrypted Internet on Linux now helps you don't shoot yourself in the foot by leaking traffic outside of the secure connection it @@ -106,6 +108,6 @@ beyond any border. The LEAP team, -July 18, 2014 +August 15, 2014 Somewhere in the middle of the intertubes. EOF diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index 8e0a3a15..2a79fafd 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -43,10 +43,6 @@ class LoginWidget(QtGui.QWidget): cancel_login = QtCore.Signal() logout = QtCore.Signal() - # Emitted when the user selects "Other..." in the provider - # combobox or click "Create Account" - show_wizard = QtCore.Signal() - MAX_STATUS_WIDTH = 40 # Keyring @@ -64,7 +60,6 @@ class LoginWidget(QtGui.QWidget): QtGui.QWidget.__init__(self, parent) self._settings = settings - self._selected_provider_index = -1 self.ui = Ui_LoginWidget() self.ui.setupUi(self) @@ -80,9 +75,6 @@ class LoginWidget(QtGui.QWidget): self.ui.lnUser.returnPressed.connect(self._focus_password) - self.ui.cmbProviders.currentIndexChanged.connect( - self._current_provider_changed) - self.ui.btnLogout.clicked.connect( self.logout) @@ -111,35 +103,6 @@ class LoginWidget(QtGui.QWidget): enable = True if state == QtCore.Qt.Checked else False self._settings.set_remember(enable) - def set_providers(self, provider_list): - """ - Set the provider list to provider_list plus an "Other..." item - that triggers the wizard - - :param provider_list: list of providers - :type provider_list: list of str - """ - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.clear() - self.ui.cmbProviders.addItems(provider_list + [self.tr("Other...")]) - self.ui.cmbProviders.blockSignals(False) - - def select_provider_by_name(self, name): - """ - Given a provider name/domain, it selects it in the combobox - - :param name: name or domain for the provider - :type name: str - """ - provider_index = self.ui.cmbProviders.findText(name) - self.ui.cmbProviders.setCurrentIndex(provider_index) - - def get_selected_provider(self): - """ - Returns the selected provider in the combobox - """ - return self.ui.cmbProviders.currentText() - def set_remember(self, value): """ Checks the remember user and password checkbox @@ -217,7 +180,6 @@ class LoginWidget(QtGui.QWidget): self.ui.lnUser.setEnabled(enabled) self.ui.lnPassword.setEnabled(enabled) self.ui.chkRemember.setEnabled(enabled and has_keyring()) - self.ui.cmbProviders.setEnabled(enabled) self._set_cancel(not enabled) @@ -258,41 +220,20 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnPassword.setFocus() - @QtCore.Slot(int) - def _current_provider_changed(self, idx): - """ - TRIGGERS: - self.ui.cmbProviders.currentIndexChanged - - :param idx: the index of the new selected item - :type idx: int - """ - if idx == (self.ui.cmbProviders.count() - 1): - self.show_wizard.emit() - # Leave the previously selected provider in the combobox - prev_provider = 0 - if self._selected_provider_index != -1: - prev_provider = self._selected_provider_index - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(prev_provider) - self.ui.cmbProviders.blockSignals(False) - else: - self._selected_provider_index = idx - - def start_login(self): + def start_login(self, provider): """ Setups the login widgets for actually performing the login and performs some basic checks. + :param provider: the domain of the current provider + :type provider: unicode str :returns: True if everything's good to go, False otherwise :rtype: bool """ username = self.get_user() password = self.get_password() - provider = self.get_selected_provider() - self._enabled_services = self._settings.get_enabled_services( - self.get_selected_provider()) + self._enabled_services = self._settings.get_enabled_services(provider) if len(provider) == 0: self.set_status( @@ -331,14 +272,16 @@ class LoginWidget(QtGui.QWidget): % (e,)) return True - def logged_in(self): + def logged_in(self, provider): """ Sets the widgets to the logged in state + + :param provider: the domain of the current provider + :type provider: unicode str """ self.ui.login_widget.hide() self.ui.logged_widget.show() - self.ui.lblUser.setText(make_address( - self.get_user(), self.get_selected_provider())) + self.ui.lblUser.setText(make_address(self.get_user(), provider)) if flags.OFFLINE is False: self.logged_in_signal.emit() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 0518350e..8ce7f2fc 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -45,6 +45,7 @@ from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard +from leap.bitmask.gui.providers import Providers from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform @@ -148,14 +149,18 @@ class MainWindow(QtGui.QMainWindow): self._mail_status = MailStatusWidget(self) self.ui.mailLayout.addWidget(self._mail_status) + # Provider List + self._providers = Providers(self.ui.cmbProviders) + # Qt Signal Connections ##################################### # TODO separate logic from ui signals. self._login_widget.login.connect(self._login) self._login_widget.cancel_login.connect(self._cancel_login) - self._login_widget.show_wizard.connect(self._launch_wizard) self._login_widget.logout.connect(self._logout) + self._providers.connect_provider_changed(self._on_provider_changed) + # EIP Control redux ######################################### self._eip_conductor = eip_conductor.EIPConductor( self._settings, self._backend, self._leap_signaler) @@ -174,6 +179,8 @@ class MainWindow(QtGui.QMainWindow): self._eip_conductor.connect_signals() self._eip_conductor.qtsigs.connected_signal.connect( self._on_eip_connection_connected) + self._eip_conductor.qtsigs.disconnected_signal.connect( + self._on_eip_connection_disconnected) self._eip_conductor.qtsigs.connected_signal.connect( self._maybe_run_soledad_setup_checks) @@ -187,7 +194,6 @@ class MainWindow(QtGui.QMainWindow): self._already_started_eip = False self._trying_to_start_eip = False - self._already_started_eip = False self._soledad_started = False # This is created once we have a valid provider config @@ -214,8 +220,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.action_wizard.triggered.connect(self._launch_wizard) self.ui.action_show_logs.triggered.connect(self._show_logger_window) self.ui.action_help.triggered.connect(self._help) + self.ui.action_create_new_account.triggered.connect( - self._launch_wizard) + self._on_provider_changed) self.ui.action_advanced_key_management.triggered.connect( self._show_AKM) @@ -502,7 +509,6 @@ class MainWindow(QtGui.QMainWindow): def _launch_wizard(self): """ TRIGGERS: - self._login_widget.show_wizard self.ui.action_wizard.triggered Also called in first run. @@ -576,7 +582,7 @@ class MainWindow(QtGui.QMainWindow): Display the Advanced Key Management dialog. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() logged_user = "{0}@{1}".format(self._logged_user, domain) details = self._provider_details @@ -599,7 +605,7 @@ class MainWindow(QtGui.QMainWindow): Display the preferences window. """ user = self._logged_user - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() mx_provided = False if self._provider_details is not None: mx_provided = MX_SERVICE in self._provider_details['services'] @@ -716,7 +722,7 @@ class MainWindow(QtGui.QMainWindow): Display the EIP preferences window. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() pref = EIPPreferencesWindow(self, domain, self._backend, self._leap_signaler) pref.show() @@ -793,7 +799,7 @@ class MainWindow(QtGui.QMainWindow): # XXX: May be this can be divided into two methods? providers = self._settings.get_configured_providers() - self._login_widget.set_providers(providers) + self._providers.set_providers(providers) self._show_systray() if not self._start_hidden: @@ -809,12 +815,12 @@ class MainWindow(QtGui.QMainWindow): # select the configured provider in the combo box domain = self._wizard.get_domain() - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) self._login_widget.set_remember(self._wizard.get_remember()) self._enabled_services = list(self._wizard.get_services()) self._settings.set_enabled_services( - self._login_widget.get_selected_provider(), + self._providers.get_selected_provider(), self._enabled_services) if possible_username is not None: self._login_widget.set_user(possible_username) @@ -831,7 +837,7 @@ class MainWindow(QtGui.QMainWindow): domain = self._settings.get_provider() if domain is not None: - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) if not self._settings.get_remember(): # nothing to do here @@ -894,11 +900,7 @@ class MainWindow(QtGui.QMainWindow): """ Set the login label to reflect offline status. """ - provider = "" - if not self._logged_in_offline: - provider = self.ui.lblLoginProvider.text() - - self.ui.lblLoginProvider.setText(provider + self.tr(" (offline mode)")) + # TODO: figure out what widget to use for this. Maybe the window title? # # systray @@ -1062,17 +1064,19 @@ class MainWindow(QtGui.QMainWindow): help_url = "<p><a href='https://{0}'>{0}</a></p>".format( self.tr("bitmask.net/help")) - lang = QtCore.QLocale.system().name().replace('_','-') + lang = QtCore.QLocale.system().name().replace('_', '-') thunderbird_extension_url = \ "https://addons.mozilla.org/{0}/" \ "thunderbird/addon/bitmask/".format(lang) email_quick_reference = self.tr("Email quick reference") - thunderbird_text = self.tr("For Thunderbird, you can use the " + thunderbird_text = self.tr( + "For Thunderbird, you can use the " "Bitmask extension. Search for \"Bitmask\" in the add-on " "manager or download it from <a href='{0}'>" "addons.mozilla.org</a>.".format(thunderbird_extension_url)) - manual_text = self.tr("Alternately, you can manually configure " + manual_text = self.tr( + "Alternately, you can manually configure " "your mail client to use Bitmask Email with these options:") manual_imap = self.tr("IMAP: localhost, port {0}".format(IMAP_PORT)) manual_smtp = self.tr("SMTP: localhost, port {0}".format(smtp_port)) @@ -1089,8 +1093,8 @@ class MainWindow(QtGui.QMainWindow): "<li> {5}</li>" "<li> {6}</li>" "</ul></p>").format(email_quick_reference, thunderbird_text, - manual_text, manual_imap, manual_smtp, - manual_username, manual_password) + manual_text, manual_imap, manual_smtp, + manual_username, manual_password) QtGui.QMessageBox.about(self, self.tr("Bitmask Help"), msg) def _needs_update(self): @@ -1156,7 +1160,7 @@ class MainWindow(QtGui.QMainWindow): emit the corresponding signals inmediately """ self._disconnect_scheduled_login() - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.provider_setup(provider=domain) @QtCore.Slot(dict) @@ -1173,7 +1177,7 @@ class MainWindow(QtGui.QMainWindow): :type data: dict """ if data[PASSED_KEY]: - selected_provider = self._login_widget.get_selected_provider() + selected_provider = self._providers.get_selected_provider() self._backend.provider_bootstrap(provider=selected_provider) else: logger.error(data[ERROR_KEY]) @@ -1201,7 +1205,8 @@ class MainWindow(QtGui.QMainWindow): eip_sigs = self._eip_conductor.qtsigs eip_sigs.connected_signal.connect(self._download_provider_config) eip_sigs.disconnected_signal.connect(self._download_provider_config) - eip_sigs.connection_aborted_signal.connect(self._download_provider_config) + eip_sigs.connection_aborted_signal.connect( + self._download_provider_config) eip_sigs.connection_died_signal.connect(self._download_provider_config) def _disconnect_scheduled_login(self): @@ -1211,17 +1216,63 @@ class MainWindow(QtGui.QMainWindow): try: eip_sigs = self._eip_conductor.qtsigs eip_sigs.connected_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.disconnected_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.connection_aborted_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.connection_died_signal.disconnect( - self._download_provider_config) + self._download_provider_config) except Exception: # signal not connected pass + @QtCore.Slot(object) + def _on_provider_changed(self, wizard=True): + """ + TRIGGERS: + self._providers._provider_changed + self.ui.action_create_new_account.triggered + + Ask the user if really wants to change provider since a services stop + is required for that action. + + :param wizard: whether the 'other...' option was picked or not. + :type wizard: bool + """ + # TODO: we should handle the case that EIP is autostarting since we + # won't get a warning until EIP has fully started. + # TODO: we need to add a check for the mail status (smtp/imap/soledad) + something_runing = (self._logged_user is not None or + self._already_started_eip) + if not something_runing: + if wizard: + self._launch_wizard() + return + + title = self.tr("Stop services") + text = "<b>" + self.tr("Do you want to stop all services?") + "</b>" + informative_text = self.tr("In order to change the provider, the " + "running services needs to be stopped.") + + msg = QtGui.QMessageBox(self) + msg.setWindowTitle(title) + msg.setText(text) + msg.setInformativeText(informative_text) + msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + msg.setDefaultButton(QtGui.QMessageBox.No) + msg.setIcon(QtGui.QMessageBox.Warning) + res = msg.exec_() + + if res == QtGui.QMessageBox.Yes: + self._stop_services() + self._eip_conductor.qtsigs.do_disconnect_signal.emit() + if wizard: + self._launch_wizard() + else: + if not wizard: + # if wizard, the widget restores itself + self._providers.restore_previous_provider() @QtCore.Slot() def _login(self): @@ -1235,19 +1286,18 @@ class MainWindow(QtGui.QMainWindow): bootstrapping the EIP service """ # TODO most of this could ve handled by the login widget, - # but we'd have to move lblLoginProvider into the widget itself, - # instead of having it as a top-level attribute. + provider = self._providers.get_selected_provider() if flags.OFFLINE is True: logger.debug("OFFLINE mode! bypassing remote login") # TODO reminder, we're not handling logout for offline # mode. - self._login_widget.logged_in() + self._login_widget.logged_in(provider) self._logged_in_offline = True self._set_label_offline() self.offline_mode_bypass_login.emit() else: self.ui.action_create_new_account.setEnabled(False) - if self._login_widget.start_login(): + if self._login_widget.start_login(provider): if self._trying_to_start_eip: self._schedule_login() else: @@ -1327,7 +1377,7 @@ class MainWindow(QtGui.QMainWindow): self._show_hide_unsupported_services() - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.user_login(provider=domain, username=username, password=password) else: @@ -1347,7 +1397,7 @@ class MainWindow(QtGui.QMainWindow): self._logged_user = self._login_widget.get_user() user = self._logged_user - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() full_user_id = make_address(user, domain) self._mail_conductor.userid = full_user_id self._start_eip_bootstrap() @@ -1370,9 +1420,8 @@ class MainWindow(QtGui.QMainWindow): triggers the eip bootstrapping. """ - self._login_widget.logged_in() - domain = self._login_widget.get_selected_provider() - self.ui.lblLoginProvider.setText(domain) + domain = self._providers.get_selected_provider() + self._login_widget.logged_in(domain) self._enabled_services = self._settings.get_enabled_services(domain) @@ -1394,7 +1443,7 @@ class MainWindow(QtGui.QMainWindow): and enabled. This is triggered right after the provider has been set up. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() lang = QtCore.QLocale.system().name() self._backend.provider_get_details(domain=domain, lang=lang) @@ -1415,7 +1464,7 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) mx_enabled = MX_SERVICE in enabled_services @@ -1432,7 +1481,7 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) eip_enabled = EIP_SERVICE in enabled_services @@ -1453,7 +1502,7 @@ class MainWindow(QtGui.QMainWindow): username = self._login_widget.get_user() password = unicode(self._login_widget.get_password()) - provider_domain = self._login_widget.get_selected_provider() + provider_domain = self._providers.get_selected_provider() if flags.OFFLINE: full_user_id = make_address(username, provider_domain) @@ -1469,7 +1518,7 @@ class MainWindow(QtGui.QMainWindow): password=password, uuid=uuid) else: if self._logged_user is not None: - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.soledad_bootstrap(username=username, domain=domain, password=password) @@ -1553,7 +1602,7 @@ class MainWindow(QtGui.QMainWindow): """ self._already_started_eip = True - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._settings.set_defaultprovider(domain) self._backend.eip_get_gateway_country_code(domain=domain) @@ -1562,6 +1611,16 @@ class MainWindow(QtGui.QMainWindow): self._backend.eip_check_dns(domain=domain) @QtCore.Slot() + def _on_eip_connection_disconnected(self): + """ + TRIGGERS: + self._eip_conductor.qtsigs.disconnected_signal + + Set the eip status to not started. + """ + self._already_started_eip = False + + @QtCore.Slot() def _set_eip_provider(self, country_code=None): """ TRIGGERS: @@ -1570,7 +1629,7 @@ class MainWindow(QtGui.QMainWindow): Set the current provider and country code in the eip status widget. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._eip_status.set_provider(domain, country_code) @QtCore.Slot() @@ -1578,7 +1637,7 @@ class MainWindow(QtGui.QMainWindow): """ Trigger this if we don't have a working DNS resolver. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() msg = self.tr( "The server at {0} can't be found, because the DNS lookup " "failed. DNS is the network service that translates a " @@ -1642,7 +1701,7 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.eip_button.hide() self._eip_status.eip_button.setEnabled(False) - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.eip_setup(provider=domain) self._already_started_eip = True @@ -1733,7 +1792,6 @@ class MainWindow(QtGui.QMainWindow): Inform the user about a logout error. """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._login_widget.set_status( self.tr("Something went wrong with the logout.")) @@ -1747,7 +1805,6 @@ class MainWindow(QtGui.QMainWindow): logging out """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._logged_user = None self._login_widget.logged_out() diff --git a/src/leap/bitmask/gui/providers.py b/src/leap/bitmask/gui/providers.py new file mode 100644 index 00000000..b3eb8620 --- /dev/null +++ b/src/leap/bitmask/gui/providers.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013,2014 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 <http://www.gnu.org/licenses/>. +# + +""" +An instance of class Providers, held by mainwindow, is responsible for +managing the current provider and the combobox provider list. +""" + +from collections import deque +from PySide import QtCore + + +class Providers(QtCore.QObject): + + # Emitted when the user changes the provider combobox index. The object + # parameter is actually a boolean value that is True if "Other..." was + # selected, False otherwse + _provider_changed = QtCore.Signal(object) + + def __init__(self, providers_combo): + """ + :param providers_combo: combo widget that lists providers + :type providers_combo: QWidget + """ + QtCore.QObject.__init__(self) + self._providers_indexes = deque(maxlen=2) # previous and current + self._providers_indexes.append(-1) + self._combo = providers_combo + self._combo.currentIndexChanged.connect( + self._current_provider_changed) + + def set_providers(self, provider_list): + """ + Set the provider list to provider_list plus an "Other..." item + that triggers the wizard + + :param provider_list: list of providers + :type provider_list: list of str + """ + self._combo.blockSignals(True) + self._combo.clear() + self._combo.addItems(provider_list + [self.tr("Other...")]) + self._combo.blockSignals(False) + + def select_provider_by_name(self, name): + """ + Given a provider name/domain, it selects it in the combobox + + :param name: name or domain for the provider + :type name: unicode str + """ + provider_index = self._combo.findText(name) + self._providers_indexes.append(provider_index) + + # block the signals during a combobox change since we don't want to + # trigger the default signal that makes the UI ask the user for + # confirmation + self._combo.blockSignals(True) + self._combo.setCurrentIndex(provider_index) + self._combo.blockSignals(False) + + def get_selected_provider(self): + """ + Returns the selected provider in the combobox + + :rtype: unicode str + """ + return self._combo.currentText() + + def connect_provider_changed(self, callback): + """ + Connects callback to provider_changed signal + """ + self._provider_changed.connect(callback) + + def restore_previous_provider(self): + """ + Set as selected provider the one that was selected previously. + """ + prev_provider = self._providers_indexes.popleft() + self._providers_indexes.append(prev_provider) + self._combo.blockSignals(True) + self._combo.setCurrentIndex(prev_provider) + self._combo.blockSignals(False) + + @QtCore.Slot(int) + def _current_provider_changed(self, idx): + """ + TRIGGERS: + self._combo.currentIndexChanged + + :param idx: the index of the new selected item + :type idx: int + """ + self._providers_indexes.append(idx) + is_wizard = idx == (self._combo.count() - 1) + self._provider_changed.emit(is_wizard) + if is_wizard: + self.restore_previous_provider() diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui index 26decc6d..bfd5f9c0 100644 --- a/src/leap/bitmask/gui/ui/login.ui +++ b/src/leap/bitmask/gui/ui/login.ui @@ -69,17 +69,7 @@ <property name="rightMargin"> <number>24</number> </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string><b>Provider:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="4" column="1"> + <item row="3" column="1"> <widget class="QPushButton" name="btnLogin"> <property name="sizePolicy"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> @@ -92,7 +82,7 @@ </property> </widget> </item> - <item row="3" column="1"> + <item row="2" column="1"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QCheckBox" name="chkRemember"> @@ -116,10 +106,7 @@ </item> </layout> </item> - <item row="0" column="1"> - <widget class="QComboBox" name="cmbProviders"/> - </item> - <item row="1" column="0"> + <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string><b>Username:</b></string> @@ -129,10 +116,10 @@ </property> </widget> </item> - <item row="1" column="1"> + <item row="0" column="1"> <widget class="QLineEdit" name="lnUser"/> </item> - <item row="2" column="0"> + <item row="1" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string><b>Password:</b></string> @@ -142,7 +129,7 @@ </property> </widget> </item> - <item row="2" column="1"> + <item row="1" column="1"> <widget class="QLineEdit" name="lnPassword"> <property name="inputMask"> <string/> diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 5dc48f29..92c13d15 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -75,7 +75,7 @@ <x>0</x> <y>0</y> <width>524</width> - <height>589</height> + <height>540</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> @@ -86,7 +86,7 @@ <number>0</number> </property> <item> - <widget class="QFrame" name="frame"> + <widget class="QFrame" name="providerFrame"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -97,29 +97,16 @@ <bool>false</bool> </property> <property name="styleSheet"> - <string notr="true">background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30);</string> + <string notr="true">QFrame#providerFrame {background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30);}</string> </property> <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="leftMargin"> - <number>24</number> - </property> - <property name="rightMargin"> - <number>24</number> - </property> <item> - <widget class="QLabel" name="lblLoginProvider"> + <widget class="QComboBox" name="cmbProviders"> <property name="font"> <font> - <weight>75</weight> - <bold>true</bold> + <pointsize>12</pointsize> </font> </property> - <property name="styleSheet"> - <string notr="true">background-color: rgba(255, 255, 255, 0); border: none;</string> - </property> - <property name="text"> - <string>Please Log In</string> - </property> </widget> </item> </layout> @@ -186,7 +173,7 @@ <item> <layout class="QVBoxLayout" name="mailLayout"> <property name="spacing"> - <number>-1</number> + <number>6</number> </property> <property name="margin"> <number>12</number> @@ -224,18 +211,18 @@ <verstretch>0</verstretch> </sizepolicy> </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="styleSheet"> - <string notr="true">background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30);</string> - </property> <property name="minimumSize"> <size> <width>0</width> <height>16</height> </size> </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true">background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30);</string> + </property> </widget> </item> </layout> @@ -319,7 +306,7 @@ <x>0</x> <y>0</y> <width>524</width> - <height>21</height> + <height>25</height> </rect> </property> <widget class="QMenu" name="menuFile"> diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index e4d6f9b3..f56b9330 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -106,6 +106,7 @@ def get_missing_helpers_dialog(): msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) msg.addButton("No, don't ask again", QtGui.QMessageBox.RejectRole) msg.setDefaultButton(QtGui.QMessageBox.Yes) + msg.setEscapeButton(QtGui.QMessageBox.No) return msg diff --git a/src/leap/bitmask/util/credentials.py b/src/leap/bitmask/util/credentials.py index 07ded17b..757ce10c 100644 --- a/src/leap/bitmask/util/credentials.py +++ b/src/leap/bitmask/util/credentials.py @@ -21,7 +21,7 @@ Credentials utilities from PySide import QtCore, QtGui WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password") -USERNAME_REGEX = r"^[A-Za-z][A-Za-z\d_\-\.]+[A-Za-z\d]$" +USERNAME_REGEX = r"^[a-z][a-z\d_\-\.]+[a-z\d]$" USERNAME_VALIDATOR = QtGui.QRegExpValidator(QtCore.QRegExp(USERNAME_REGEX)) @@ -69,7 +69,7 @@ def password_checks(username, password, password2): if message is None and not password: message = _tr("You can't use an empty password") - if message is None and len(password) < 6: + if message is None and len(password) < 8: message = _tr("Password too short") if message is None and password in WEAK_PASSWORDS: |