From 26b7c725ec519abeb463d946049081b4f5d3cdae Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 15 Aug 2014 15:37:42 -0300 Subject: Add helpers and dependencies installation. --- pkg/scripts/bootstrap_develop.sh | 48 +++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/pkg/scripts/bootstrap_develop.sh b/pkg/scripts/bootstrap_develop.sh index 7027a908..68edcd43 100755 --- a/pkg/scripts/bootstrap_develop.sh +++ b/pkg/scripts/bootstrap_develop.sh @@ -159,6 +159,32 @@ update() { finish } +helpers() { + if [[ "$1" == "cleanup" ]]; then + status="removing helper files" + echo "${cc_green}Status: $status...${cc_normal}" + set -x + sudo rm -f /usr/sbin/bitmask-root + sudo rm -f /usr/share/polkit-1/actions/se.leap.bitmask.policy + set +x + else + status="installing helper files" + echo "${cc_green}Status: $status...${cc_normal}" + set -x + sudo cp bitmask_client/pkg/linux/bitmask-root /usr/sbin/ + sudo cp bitmask_client/pkg/linux/polkit/se.leap.bitmask.policy /usr/share/polkit-1/actions/ + set +x + fi +} + +install_dependencies() { + status="installing system dependencies" + echo "${cc_green}Status: $status...${cc_normal}" + set -x + sudo apt-get install -y git python-dev python-setuptools python-virtualenv python-pip libssl-dev python-openssl libsqlite3-dev g++ openvpn pyside-tools python-pyside libffi-dev + set +x +} + run() { shift # remove 'run' from arg list passthrough_args=$@ @@ -174,13 +200,17 @@ help() { echo "Bootstraps the environment to start developing the bitmask client" echo "with all the needed repositories and dependencies." echo - echo "Usage: $0 {init | update | run | help}" + echo "Usage: $0 {init | update | run | help | deps | helpers}" echo - echo " init : Initialize repositories, create virtualenv and \`python setup.py develop\` all." - echo " You can use \`init ro\` in order to use the https remotes if you don't have rw access." - echo " update : Update the repositories and install new deps (if needed)." - echo " run : Runs the client (any extra parameters will be sent to the app)." - echo " help : Show this help" + echo " init : Initialize repositories, create virtualenv and \`python setup.py develop\` all." + echo " You can use \`init ro\` in order to use the https remotes if you don't have rw access." + echo " update : Update the repositories and install new deps (if needed)." + echo " run : Runs the client (any extra parameters will be sent to the app)." + echo " help : Show this help" + echo " -- system helpers --" + echo " deps : Install the system dependencies needed for bitmask dev (Debian based Linux only)." + echo " helpers : Install the helper files needed to use bitmask (Linux only)." + echo " You can use \`helpers cleanup\` to remove those files." echo } @@ -191,6 +221,12 @@ case "$1" in update) update ;; + helpers) + helpers $2 + ;; + deps) + install_dependencies + ;; run) run "$@" ;; -- cgit v1.2.3 From 7fcc4f40eaa8214de8ae20cd71d173337ad64290 Mon Sep 17 00:00:00 2001 From: drebs Date: Mon, 18 Aug 2014 11:36:09 -0300 Subject: Fix soledad imports (#5989). --- changes/bug_5989_fix-soledad-imports | 1 + src/leap/bitmask/backend/components.py | 2 +- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 changes/bug_5989_fix-soledad-imports diff --git a/changes/bug_5989_fix-soledad-imports b/changes/bug_5989_fix-soledad-imports new file mode 100644 index 00000000..3b425287 --- /dev/null +++ b/changes/bug_5989_fix-soledad-imports @@ -0,0 +1 @@ +- Fix soledad imports (#5989). diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index f721086b..960a922e 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -60,7 +60,7 @@ from leap.common import certs as leap_certs from leap.keymanager import openpgp from leap.keymanager.errors import KeyAddressMismatch, KeyFingerprintMismatch -from leap.soledad.client import NoStorageSecret, PassphraseTooShort +from leap.soledad.client.secrets import NoStorageSecret, PassphraseTooShort logger = logging.getLogger(__name__) diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index c4e43bfe..745645f3 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -45,7 +45,8 @@ from leap.common.files import which from leap.keymanager import KeyManager, openpgp from leap.keymanager.errors import KeyNotFound from leap.soledad.common.errors import InvalidAuthTokenError -from leap.soledad.client import Soledad, BootstrapSequenceError +from leap.soledad.client import Soledad +from leap.soledad.client.secrets import BootstrapSequenceError logger = logging.getLogger(__name__) -- cgit v1.2.3 From 6fcfd7302e57ac521ba74370ac7969e2bd673f5b Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 18 Aug 2014 10:37:52 -0500 Subject: minor corrections to relnotes --- relnotes.txt | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/relnotes.txt b/relnotes.txt index 183d1f86..f2d28413 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -17,15 +17,6 @@ The Encrypted Internet Proxy provides circumvention, location anonymization, and traffic encryption in a hassle-free, automatically self-configuring fashion. -WARNING (LINUX ONLY): If you ever run into the situation where you -cannot access internet, open the terminal and run the following -command: - -$ pkexec /usr/local/sbin/bitmask-root firewall stop - -If for some reason that doesn't work, you will need to reboot your -computer. - Encrypted Mail offers automatic encryption and decryption for both outgoing and incoming email, adding public key cryptography to your mail without you ever having to worry about key distribution or @@ -48,12 +39,12 @@ 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 +OpenVPN, 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 -establishes. This will be added to other platforms in the future. +Encrypted Internet on Linux now avoids leaking traffic outside of +the secure connection it establishes. This will be added to other +platforms in the future. The Encrypted Mail services will run local SMTP and IMAP proxies that, once you configure the mail client of your choice, will automatically @@ -89,8 +80,8 @@ repository to your apt sources: deb http://deb.leap.se/debian wheezy main -We will love to hear if you are interested in help making packages -available for any other system. +We will love to hear if you want to make packages available for any +other system. BUGS @@ -98,6 +89,16 @@ You can send the bugs our way by pointing your telnet session to port 443 on https://leap.se/code. We will do our best to make them follow our intensive bug-reeducation program. + +LINUX ONLY: If you ever run into the situation where you cannot +access internet, open the terminal and run the following command: + +$ pkexec /usr/local/sbin/bitmask-root firewall stop + +If for some reason that doesn't work, you will need to reboot your +computer. + + HACKING You can find us in the #leap channel on the freenode network. -- cgit v1.2.3 From 9f8c6bdda8ca6274e2d013d6528ab4ff83b35654 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 18 Aug 2014 22:02:09 -0500 Subject: make the login not wait for eip it cannot-start-eip --- src/leap/bitmask/backend/components.py | 2 +- src/leap/bitmask/gui/mainwindow.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 960a922e..89f3c5a6 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -665,7 +665,7 @@ class EIP(object): return False client_cert_path = eip_config.\ - get_client_cert_path(provider_config, about_to_download=False) + get_client_cert_path(provider_config, about_to_download=True) if leap_certs.should_redownload(client_cert_path): logger.error("The client should redownload the certificate," diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 8ce7f2fc..70a3f388 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -703,6 +703,10 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.disable_eip_start() self._eip_status.set_eip_status(self.tr("Disabled")) + # this state flag is responsible for deferring the login + # so we must update it, otherwise we're in a deadlock. + self._trying_to_start_eip = False + @QtCore.Slot() def _disable_eip_missing_helpers(self): """ -- cgit v1.2.3 From 7259ec3425d58284961f675d5a4689681a68756a Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 18 Aug 2014 22:30:07 -0500 Subject: changes file --- changes/bug_5994_do-not-wait-for-eip-if-cannot-start | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/bug_5994_do-not-wait-for-eip-if-cannot-start diff --git a/changes/bug_5994_do-not-wait-for-eip-if-cannot-start b/changes/bug_5994_do-not-wait-for-eip-if-cannot-start new file mode 100644 index 00000000..7ada612a --- /dev/null +++ b/changes/bug_5994_do-not-wait-for-eip-if-cannot-start @@ -0,0 +1 @@ +- Login shall not wait for eip to finish if eip is not able to start. Closes: #5994 -- cgit v1.2.3 From abd476bffb427bd0733dcf87d12fed00d4cf6aaf Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 19 Aug 2014 11:27:29 -0500 Subject: remove dict comprenhension --- changes/bug-remove-dict-comprenhension | 1 + src/leap/bitmask/util/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/bug-remove-dict-comprenhension diff --git a/changes/bug-remove-dict-comprenhension b/changes/bug-remove-dict-comprenhension new file mode 100644 index 00000000..4e9468d8 --- /dev/null +++ b/changes/bug-remove-dict-comprenhension @@ -0,0 +1 @@ +- Remove dict comprenension in util, for 2.6 compat. diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py index caa94ec7..e8eddd64 100644 --- a/src/leap/bitmask/util/__init__.py +++ b/src/leap/bitmask/util/__init__.py @@ -151,6 +151,6 @@ def flags_to_dict(): :rtype: dict. """ items = [i for i in dir(flags) if i[0] != '_'] - values = {i: getattr(flags, i) for i in items} + values = dict((i, getattr(flags, i)) for i in items) return values -- cgit v1.2.3 From c23f2bef3b18e02069720188e1d460c1f2687180 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 19 Aug 2014 17:49:34 -0300 Subject: Change settings' provider on provider change. Closes #5995. --- changes/bug-5995_save-provider-on-change | 1 + src/leap/bitmask/gui/mainwindow.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 changes/bug-5995_save-provider-on-change diff --git a/changes/bug-5995_save-provider-on-change b/changes/bug-5995_save-provider-on-change new file mode 100644 index 00000000..e0f86d75 --- /dev/null +++ b/changes/bug-5995_save-provider-on-change @@ -0,0 +1 @@ +- Save default provider if changed on the combo box. Closes #5995. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 70a3f388..60605b48 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1249,9 +1249,14 @@ class MainWindow(QtGui.QMainWindow): # 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) + provider = self._providers.get_selected_provider() + if not something_runing: if wizard: self._launch_wizard() + else: + self._settings.set_provider(provider) + self._settings.set_defaultprovider(provider) return title = self.tr("Stop services") @@ -1269,6 +1274,9 @@ class MainWindow(QtGui.QMainWindow): res = msg.exec_() if res == QtGui.QMessageBox.Yes: + self._settings.set_provider(provider) + self._settings.set_defaultprovider(provider) + self._settings.set_autostart_eip(False) self._stop_services() self._eip_conductor.qtsigs.do_disconnect_signal.emit() if wizard: -- cgit v1.2.3 From ced7ebf5407c23c3af585db4e0749c311114272f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 19 Aug 2014 18:04:04 -0300 Subject: Update and get ready to start a provider on change. Closes #5996, #5997. --- changes/bug-5996_update-eip-status-on-change | 1 + changes/bug-5997_get-ready-provider-on-change | 1 + src/leap/bitmask/gui/mainwindow.py | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 changes/bug-5996_update-eip-status-on-change create mode 100644 changes/bug-5997_get-ready-provider-on-change diff --git a/changes/bug-5996_update-eip-status-on-change b/changes/bug-5996_update-eip-status-on-change new file mode 100644 index 00000000..665092f0 --- /dev/null +++ b/changes/bug-5996_update-eip-status-on-change @@ -0,0 +1 @@ +- Update the EIP status on provider change. Closes #5996. diff --git a/changes/bug-5997_get-ready-provider-on-change b/changes/bug-5997_get-ready-provider-on-change new file mode 100644 index 00000000..e6b3f7f1 --- /dev/null +++ b/changes/bug-5997_get-ready-provider-on-change @@ -0,0 +1 @@ +- Update and get ready to start a provider on change. Closes #5997. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 60605b48..59896bbb 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1257,6 +1257,7 @@ class MainWindow(QtGui.QMainWindow): else: self._settings.set_provider(provider) self._settings.set_defaultprovider(provider) + self._update_eip_enabled_status() return title = self.tr("Stop services") @@ -1278,6 +1279,7 @@ class MainWindow(QtGui.QMainWindow): self._settings.set_defaultprovider(provider) self._settings.set_autostart_eip(False) self._stop_services() + self._update_eip_enabled_status() self._eip_conductor.qtsigs.do_disconnect_signal.emit() if wizard: self._launch_wizard() -- cgit v1.2.3 From b6ab5790e8b2ac0d67bf0eb40e474b8bed4c42dd Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 20 Aug 2014 15:10:02 -0300 Subject: Select current provider on EIP preferences. - Don't disconnect logout signals, so when the wizard is triggered the UI can reflect the logout result. - Restore the selected provider when 'other...' is selected *before* the provider_changed signal is emitted to avoid that option to keep selected in case of some error. - Avoid the currentIndexChanged to be triggered when we load the providers. --- changes/bug-5815_eip-preferences-issues | 2 ++ src/leap/bitmask/gui/eip_preferenceswindow.py | 3 +++ src/leap/bitmask/gui/mainwindow.py | 11 +++++------ src/leap/bitmask/gui/providers.py | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 changes/bug-5815_eip-preferences-issues diff --git a/changes/bug-5815_eip-preferences-issues b/changes/bug-5815_eip-preferences-issues new file mode 100644 index 00000000..013fe03d --- /dev/null +++ b/changes/bug-5815_eip-preferences-issues @@ -0,0 +1,2 @@ +- Select current provider on EIP preferences. Closes #5815. +- Handle logout correctly when we stop_services to launch the wizard. Related to #5815. diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py index 0f63972f..b5788f3c 100644 --- a/src/leap/bitmask/gui/eip_preferenceswindow.py +++ b/src/leap/bitmask/gui/eip_preferenceswindow.py @@ -116,11 +116,14 @@ class EIPPreferencesWindow(QtGui.QDialog): self.ui.gbGatewaySelector.setEnabled(False) return + # block signals so the currentIndexChanged slot doesn't get triggered + self.ui.cbProvidersGateway.blockSignals(True) for provider, is_initialized in providers: label = provider if not is_initialized: label += self.tr(" (uninitialized)") self.ui.cbProvidersGateway.addItem(label, userData=provider) + self.ui.cbProvidersGateway.blockSignals(False) # Select provider by name domain = self._selected_domain diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 59896bbb..e086d02a 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -413,11 +413,6 @@ class MainWindow(QtGui.QMainWindow): "Invalid username or password.")) conntrack(sig.srp_auth_bad_user_or_password, auth_bad_user_or_password) - # Logout signals - conntrack(sig.srp_logout_ok, self._logout_ok) - conntrack(sig.srp_logout_error, self._logout_error) - conntrack(sig.srp_not_logged_in_error, self._not_logged_in_error) - # EIP bootstrap signals conntrack(sig.eip_config_ready, self._eip_intermediate_stage) conntrack(sig.eip_client_certificate_ready, self._finish_eip_bootstrap) @@ -436,8 +431,12 @@ class MainWindow(QtGui.QMainWindow): sig.prov_unsupported_api.connect(self._incompatible_api) sig.prov_get_all_services.connect(self._provider_get_all_services) - # EIP start signals ============================================== + # Logout signals ================================================= + sig.srp_logout_ok.connect(self._logout_ok) + sig.srp_logout_error.connect(self._logout_error) + sig.srp_not_logged_in_error.connect(self._not_logged_in_error) + # EIP start signals ============================================== self._eip_conductor.connect_backend_signals() sig.eip_can_start.connect(self._backend_can_start_eip) sig.eip_cannot_start.connect(self._backend_cannot_start_eip) diff --git a/src/leap/bitmask/gui/providers.py b/src/leap/bitmask/gui/providers.py index b3eb8620..6954411f 100644 --- a/src/leap/bitmask/gui/providers.py +++ b/src/leap/bitmask/gui/providers.py @@ -109,6 +109,6 @@ class Providers(QtCore.QObject): """ 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() + self._provider_changed.emit(is_wizard) -- cgit v1.2.3 From ac83b8900bb8d31e6f1f1fa983435659625ff91f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 22 Aug 2014 17:25:52 -0300 Subject: Hide button / improve message on missing helpers. * Emit the `eip_missing_helpers` signal when the user chooses "Don't ask me again". * We emit that signal when some helper file is missing, even if the user doesn't want a warning. * Do the update of the eip enabled status with some delay to give some time the eip machine to start and do what it needs with the buttons/labels and avoid the 'hide turn on button if missing files' being overridden. Closes #5945. --- changes/bug-5945_not-adding-helper-files | 1 + src/leap/bitmask/gui/eip_status.py | 3 +-- src/leap/bitmask/gui/mainwindow.py | 19 ++++++++++++++++--- src/leap/bitmask/platform_init/initializers.py | 7 +++++++ 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 changes/bug-5945_not-adding-helper-files diff --git a/changes/bug-5945_not-adding-helper-files b/changes/bug-5945_not-adding-helper-files new file mode 100644 index 00000000..94e41c25 --- /dev/null +++ b/changes/bug-5945_not-adding-helper-files @@ -0,0 +1 @@ +- Hide button and display correct warning on missing helpers files. Closes #5945. diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index abd6e2c9..1c167335 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -303,7 +303,6 @@ class EIPStatusWidget(QtGui.QWidget): """ # XXX this name is unfortunate. "disable" is also applied to a # pushbutton being grayed out. - 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. @@ -334,7 +333,7 @@ class EIPStatusWidget(QtGui.QWidget): Triggered after a successful login. Enables the start button. """ - # logger.debug('Showing EIP start button') + logger.debug('Showing EIP start button') self.eip_button.show() self.hide_eip_cancel_button() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index e086d02a..6c168a19 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -656,6 +656,10 @@ class MainWindow(QtGui.QMainWindow): to do so, start it. Otherwise it leaves everything in place for the user to click Turn ON. """ + if self._eip_status.missing_helpers: + self._eip_status.disable_eip_start() + return + settings = self._settings default_provider = settings.get_defaultprovider() enabled_services = [] @@ -700,7 +704,9 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.disable_eip_start() else: self._eip_status.disable_eip_start() - self._eip_status.set_eip_status(self.tr("Disabled")) + # NOTE: we shouldn't be setting the message here. + if not self._eip_status.missing_helpers: + self._eip_status.set_eip_status(self.tr("Disabled")) # this state flag is responsible for deferring the login # so we must update it, otherwise we're in a deadlock. @@ -812,6 +818,15 @@ class MainWindow(QtGui.QMainWindow): self._show_hide_unsupported_services() + # XXX - HACK, kind of... + # With the 1ms QTimer.singleShot call we schedule the call right after + # other signals waiting for the qt reactor to take control. + # That way, the method is called right after the EIP machines' signals. + # We need to wait until that happens because the state-machine + # controlled widget shows the 'Turn On' button and we want to do the + # changes to that button right after, not before. + QtDelayedCall(1, self._update_eip_enabled_status) + if self._wizard: possible_username = self._wizard.get_username() possible_password = self._wizard.get_password() @@ -836,8 +851,6 @@ class MainWindow(QtGui.QMainWindow): self._wizard = None self._backend_connect(only_tracked=True) else: - self._update_eip_enabled_status() - domain = self._settings.get_provider() if domain is not None: self._providers.select_provider_by_name(domain) diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index f56b9330..6c62734c 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -164,6 +164,7 @@ def check_missing(): logger.debug( "Setting alert_missing_scripts to False, we will not " "ask again") + init_signals.eip_missing_helpers.emit() config.set_alert_missing_scripts(False) if complain_missing and missing_some: @@ -171,6 +172,12 @@ def check_missing(): msg = _get_missing_complain_dialog(missing) ret = msg.exec_() + # If there is some missing file and we don't want to complain, we emit the + # 'missing helpers' signal so the eip status can show that some files are + # missing. + if missing_some and not alert_missing and not complain_missing: + init_signals.eip_missing_helpers.emit() + # # windows initializers # -- cgit v1.2.3 From ad85a375eb74609c8a1d7a7a3a0a11b7489a2483 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 28 Aug 2014 10:42:53 -0300 Subject: Remove /tmp/bitmask.lock on quit. Closes #5866. Add a platform independent release_lock helper, so all the SO dependent code goes inside the locks file. Also, do some code cleanup. --- changes/bug-5866_bitmask-lock-not-removed | 1 + src/leap/bitmask/gui/mainwindow.py | 10 ++---- src/leap/bitmask/platform_init/locks.py | 59 ++++++++++++++++++++----------- 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 changes/bug-5866_bitmask-lock-not-removed diff --git a/changes/bug-5866_bitmask-lock-not-removed b/changes/bug-5866_bitmask-lock-not-removed new file mode 100644 index 00000000..d68c1122 --- /dev/null +++ b/changes/bug-5866_bitmask-lock-not-removed @@ -0,0 +1 @@ +- /tmp/bitmask.lock not removed. Closes #5866. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 6c168a19..653ebc35 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -48,6 +48,7 @@ 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 import locks from leap.bitmask.platform_init.initializers import init_platform from leap.bitmask.platform_init.initializers import init_signals @@ -63,10 +64,6 @@ from leap.bitmask.util import autostart, make_address from leap.bitmask.util.keyring_helpers import has_keyring from leap.bitmask.logs.leap_log_handler import LeapLogHandler -if IS_WIN: - from leap.bitmask.platform_init.locks import WindowsLock - from leap.bitmask.platform_init.locks import raise_window_ack - from leap.common.events import register from leap.common.events import events_pb2 as proto @@ -1865,7 +1862,7 @@ class MainWindow(QtGui.QMainWindow): Callback for the raise window event """ if IS_WIN: - raise_window_ack() + locks.raise_window_ack() self.raise_window.emit() @QtCore.Slot() @@ -2022,7 +2019,6 @@ class MainWindow(QtGui.QMainWindow): # Remove lockfiles on a clean shutdown. logger.debug('Cleaning pidfiles') - if IS_WIN: - WindowsLock.release_all_locks() + locks.release_lock() self.close() diff --git a/src/leap/bitmask/platform_init/locks.py b/src/leap/bitmask/platform_init/locks.py index 78ebf4cd..ac45a5ce 100644 --- a/src/leap/bitmask/platform_init/locks.py +++ b/src/leap/bitmask/platform_init/locks.py @@ -22,11 +22,11 @@ import errno import os import platform -from leap.bitmask import platform_init +from leap.bitmask.platform_init import IS_WIN, IS_UNIX from leap.common.events import signal as signal_event from leap.common.events import events_pb2 as proto -if platform_init.IS_UNIX: +if IS_UNIX: from fcntl import flock, LOCK_EX, LOCK_NB else: # WINDOWS import datetime @@ -40,7 +40,7 @@ else: # WINDOWS logger = logging.getLogger(__name__) -if platform_init.IS_UNIX: +if IS_UNIX: class UnixLock(object): """ @@ -48,14 +48,13 @@ if platform_init.IS_UNIX: See man 2 flock """ - def __init__(self, path): + _LOCK_FILE = '/tmp/bitmask.lock' + + def __init__(self): """ - iniializes t he UnixLock with the path of the - desired lockfile + Initialize the UnixLock. """ - self._fd = None - self.path = path def get_lock(self): """ @@ -77,7 +76,7 @@ if platform_init.IS_UNIX: :rtype: bool """ - self._fd = os.open(self.path, os.O_CREAT | os.O_RDWR) + self._fd = os.open(self._LOCK_FILE, os.O_CREAT | os.O_RDWR) try: flock(self._fd, LOCK_EX | LOCK_NB) @@ -102,6 +101,21 @@ if platform_init.IS_UNIX: gotit, pid = self._get_lock_and_pid() return pid == os.getpid() + @classmethod + def release_lock(self): + """ + Release the lock. + + :return: True if the lock was released, False otherwise + :rtype: bool + """ + try: + os.remove(self._LOCK_FILE) + return True + except Exception as e: + logger.debug("Problem removing lock, {0!r}".format(e)) + return False + def _get_lock_and_pid(self): """ Tries to get a lock over the file. @@ -109,7 +123,6 @@ if platform_init.IS_UNIX: :rtype: tuple """ - if self._get_lock(): self._write_to_pidfile() return True, None @@ -121,9 +134,7 @@ if platform_init.IS_UNIX: Tries to read pid from the pidfile, returns False if no content found. """ - - pidfile = os.read( - self._fd, 16) + pidfile = os.read(self._fd, 16) if not pidfile: return False @@ -144,7 +155,7 @@ if platform_init.IS_UNIX: os.fsync(fd) -if platform_init.IS_WIN: +if IS_WIN: # Time to wait (in secs) before assuming a raise window signal has not been # ack-ed. @@ -348,17 +359,15 @@ def we_are_the_one_and_only(): :rtype: bool """ - _sys = platform.system() - - if _sys in ("Linux", "Darwin"): - locker = UnixLock('/tmp/bitmask.lock') + if IS_UNIX: + locker = UnixLock() locker.get_lock() we_are_the_one = locker.locked_by_us if not we_are_the_one: signal_event(proto.RAISE_WINDOW) return we_are_the_one - elif _sys == "Windows": + elif IS_WIN: locker = WindowsLock() locker.get_lock() we_are_the_one = locker.locked_by_us @@ -398,6 +407,16 @@ def we_are_the_one_and_only(): else: logger.warning("Multi-instance checker " - "not implemented for %s" % (_sys)) + "not implemented for %s" % (platform.system())) # lies, lies, lies... return True + + +def release_lock(): + """ + Release the acquired lock. + """ + if IS_WIN: + WindowsLock.release_all_locks() + elif IS_UNIX: + UnixLock.release_lock() -- cgit v1.2.3 From d24fedb34caefd96ac68a98dbe42e36e9ca6c7c9 Mon Sep 17 00:00:00 2001 From: Bruno Wagner Goncalves Date: Tue, 2 Sep 2014 16:30:33 -0300 Subject: Removed hard coded path of python app on mac platform --- pkg/postmkvenv.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/postmkvenv.sh b/pkg/postmkvenv.sh index 04f8d372..9c6debe8 100755 --- a/pkg/postmkvenv.sh +++ b/pkg/postmkvenv.sh @@ -27,7 +27,7 @@ LIB_VIRTUALENV_PATH=$(python -c "$GET_PYTHON_LIB_CMD") if [[ $platform == 'linux' ]]; then LIB_SYSTEM_PATH=$(${VAR[-1]} -c "$GET_PYTHON_LIB_CMD") elif [[ $platform == 'darwin' ]]; then - LIB_SYSTEM_PATH=$(/opt/local/bin/python2.6 -c "$GET_PYTHON_LIB_CMD") + LIB_SYSTEM_PATH=$(python -c "$GET_PYTHON_LIB_CMD") else echo "unsupported platform; not doing symlinks" fi -- cgit v1.2.3 From 1d0c1c4701c0fd2c18bbbb6910de44bd0a5f4bba Mon Sep 17 00:00:00 2001 From: Bruno Wagner Goncalves Date: Tue, 2 Sep 2014 19:29:42 -0300 Subject: Temporarily removing venv from path, to get system lib folder --- pkg/postmkvenv.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/postmkvenv.sh b/pkg/postmkvenv.sh index 9c6debe8..7b06fa6d 100755 --- a/pkg/postmkvenv.sh +++ b/pkg/postmkvenv.sh @@ -27,7 +27,13 @@ LIB_VIRTUALENV_PATH=$(python -c "$GET_PYTHON_LIB_CMD") if [[ $platform == 'linux' ]]; then LIB_SYSTEM_PATH=$(${VAR[-1]} -c "$GET_PYTHON_LIB_CMD") elif [[ $platform == 'darwin' ]]; then + ORIGINAL_PATH=$PATH + #change first colon of path to | because path substitution is greedy + PATH=${PATH/:/|} + #remove everything up to | from path + PATH=${PATH/*|/} LIB_SYSTEM_PATH=$(python -c "$GET_PYTHON_LIB_CMD") + PATH=$ORIGINAL_PATH else echo "unsupported platform; not doing symlinks" fi -- cgit v1.2.3 From 38e3ec8d500e3d22c286932a065f2a0c0b8f0e1c Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 3 Sep 2014 10:38:22 -0500 Subject: add /es/ locale to resources --- data/resources/locale.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/data/resources/locale.qrc b/data/resources/locale.qrc index ba466c36..787b0025 100644 --- a/data/resources/locale.qrc +++ b/data/resources/locale.qrc @@ -2,5 +2,6 @@ ../translations/vi.qm ../translations/en_GB.qm +../translations/es.qm -- cgit v1.2.3 From 3655f2d5651e7cff47cf0f869e7b794bae247aed Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 3 Sep 2014 10:38:40 -0500 Subject: update en_US translation file --- data/ts/en_US.ts | 626 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 322 insertions(+), 304 deletions(-) diff --git a/data/ts/en_US.ts b/data/ts/en_US.ts index cf74d7b6..041cdc44 100644 --- a/data/ts/en_US.ts +++ b/data/ts/en_US.ts @@ -172,7 +172,7 @@ Export canceled. ComplainDialog - + Ok, thanks @@ -228,22 +228,22 @@ Export canceled. - + Gateway settings for provider '{0}' saved. - + There was a problem with configuration files. - + (uninitialized) - + This is an uninitialized provider, please log in first. @@ -261,12 +261,12 @@ Export canceled. - + ... - + Traffic is being routed in the clear @@ -280,149 +280,187 @@ Export canceled. Turn Off + + + Cancel + + EIPStatusWidget - + Turn ON - + Authenticating... - + Retrieving configuration... - + Waiting to start... - + Assigning IP - + Reconnecting... - + Unable to start VPN, it's already running. - + disabled - + {0}: OFF - + You must login to use {0} - + {0}: Starting... - + {0}: ON - + Encrypted Internet is starting - + Retry - + Traffic is being routed in the clear. - + Network is unreachable. - + Error connecting - + Error connecting. - + Bitmask is blocking unencrypted traffic. - + Routing traffic through: <b>{0}</b> - + Could not load {0} configuration. - + Another openvpn instance is already running, and could not be stopped. - + Another openvpn instance is already running, and could not be stopped because it was not launched by Bitmask. Please stop it and try again. - + We could not find openvpn binary. - + We could not find any authentication agent in your system.<br/>Make sure you have<b>polkit-gnome-authentication-agent-1</b> running andtry again. - + We could not find <b>pkexec</b> in your system. - + {0} cannot be started because the tuntap extension is not installed properly in your system. - + Network is unreachable + + + <font color=red>Disabled: missing helper files</font> + + + + + VPN Launcher error. See the logs for more info. + + + + + Encrypted Internet failed to start + + + + + Form + + + Form + + + + + ... + + + + + Logout + + LoggerWindow @@ -462,7 +500,7 @@ Export canceled. - + Save As @@ -477,37 +515,37 @@ Export canceled. - + Send to Pastebin.com - + Sending to pastebin... - + Your pastebin link <a href='{0}'>{0}</a> - + Pastebin OK - + Sending logs to Pastebin failed! - + Pastebin Error - + Maximum posts per day reached @@ -520,72 +558,62 @@ Export canceled. - - <b>Provider:</b> - - - - + Remember username and password - + <b>Username:</b> - + <b>Password:</b> - + Log In - - Other... - - - - + Cancel - + ... - + Logout - + Please select a valid provider - + Please provide a valid username - + Please provide a valid password - + Logging in... - + Logging out... @@ -657,11 +685,6 @@ Export canceled. Soledad is starting, please wait... - - - Looking for key for this user - - Found key! Starting mail... @@ -732,72 +755,72 @@ Export canceled. Starting… + + + Initial sync in progress, please wait... + + MainWindow - + There are new updates available, please restart. - + More... - + Help - + &Quit - + &Help - + &Wizard - - Hide Main Window - - - - + The following components will be updated: %s - + Updates available - + Show Main Window - + Starting... - + Not supported - + Disabled @@ -807,205 +830,255 @@ Export canceled. - + About &Bitmask - + Mail is OFF - + The Bitmask app is ready to update, please restart the application. - + About Bitmask - %s - + Unable to login: Problem with provider - + Log in cancelled by the user. - + There was a problem with the provider - + Something went wrong with the logout. - + Unable to connect: Problem with provider - - Login - - - - + &Bitmask - + Show &Log - + Create a new account... - + File - - Please Log In - - - - + Account Preferences... - + Internet Preferences... - + Advanced Key Management - - (offline mode) - - - - + OFF - + Version: <b>%s</b> (%s)<br><br>%sBitmask is the Desktop client application for the LEAP platform, supporting encrypted internet proxy, secure email, and secure chat (coming soon).<br><br>LEAP is a non-profit dedicated to giving all internet users access to secure communication. Our focus is on adapting encryption technology to make it easy to use and widely available. <br><br><a href='https://leap.se'>More about LEAP</a> - - <strong>Instructions to use mail:</strong><br>If you use Thunderbird you can use the Bitmask extension helper. Search for 'Bitmask' in the add-on manager or download it from: {0}.<br><br>You can configure Bitmask manually with these options:<br><em> Incoming -> IMAP, port: {1}<br> Outgoing -> SMTP, port: {2}<br> Username -> your bitmask username.<br> Password -> does not matter, use any text. Just don't leave it empty and don't use your account's password.</em> - - - - + Bitmask Help - + The current client version is not supported by this provider.<br>Please update to latest version.<br><br>You can get the latest version from <a href='{0}'>{1}</a> - + Update Needed - + This provider is not compatible with the client.<br><br>Error: API version incompatible. - + Incompatible Provider - + Application error - + You are trying to do an operation that requires logging in first. - + Unknown error. - + There was a server problem with authentication. - + Could not establish a connection. - + Invalid username or password. - + Hello! - + Bitmask has started in the tray. - + Succeeded - + The server at {0} can't be found, because the DNS lookup failed. DNS is the network service that translates a website's name to its Internet address. Either your computer is having trouble connecting to the network, or you are missing some helper files that are needed to securely use DNS while {1} is active. To install these helper files, quit this application and start it again. - + Connection Error - + Quitting... - + Bitmask is quitting, please wait. + + + There is a problem contacting the backend, please restart Bitmask. + + + + + bitmask.net/help + + + + + Email quick reference + + + + + 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>. + + + + + Alternately, you can manually configure your mail client to use Bitmask Email with these options: + + + + + IMAP: localhost, port {0} + + + + + SMTP: localhost, port {0} + + + + + Username: your full email address + + + + + Password: any non-empty text + + + + + <p><strong>{0}</strong></p><p>{1}</p><p>{2}<ul><li>&nbsp;{3}</li><li>&nbsp;{4}</li><li>&nbsp;{5}</li><li>&nbsp;{6}</li></ul></p> + + + + + Stop services + + + + + Do you want to stop all services? + + + + + In order to change the provider, the running services needs to be stopped. + + + + + Disabled: missing helper files + + Preferences @@ -1078,47 +1151,47 @@ Export canceled. PreferencesWindow - + Automatic - + Changing password... - + Password changed successfully. - + There was a problem changing the password. - + You did not enter a correct current password. - + Services settings for provider '{0}' saved. - + You need to enable {0} in order to change the password. - + You need to wait until {0} is ready in order to change the password. - + In order to change your password you need to be logged in. @@ -1137,12 +1210,15 @@ Export canceled. - Wizard + Providers - - Welcome + + Other... + + + Wizard Log In with my credentials @@ -1154,22 +1230,12 @@ Export canceled. - - Provider selection - - - - - Please enter the domain of the provider you want to use for your connection - - - - + Check - + https:// @@ -1179,310 +1245,275 @@ Export canceled. - - Getting provider information - - - - + Can we reach this provider? - - Provider Information - - - - - Description of services offered by this provider - - - - + Name - + Desc - + <b>Services offered:</b> - + services - + <b>Enrollment policy:</b> - + policy - + <b>URL:</b> - + URL - + <b>Description:</b> - + Provider setup - - Gathering configuration options for this provider - - - - - We are downloading some bits that we need to establish a secure connection with the provider for the first time. - - - - + Setting up provider - - Getting info from the Certificate Authority - - - - - Do we trust this Certificate Authority? - - - - - Establishing a trust relationship with this provider - - - - + Register new user - - Register a new user with provider - - - - + <b>Password:</b> - + <b>Re-enter password:</b> - + Register - + Remember my username and password - + Service selection - - Please select the services you would like to have - - - - + &Next > - + Connect - + Starting registration... - + User %s successfully registered. - + <font color='red'><b>Non-existent provider</b></font> - + <font color='red'><b>%s</b></font> - + Unable to load provider configuration - + <font color='red'><b>Not a valid provider</b></font> - + Something went wrong while trying to load service %s - - - Bitmask first run - - - - - This is the Bitmask first run wizard - - Can we establish a secure connection? - + <b>Username:</b> - + Configure or select a provider - + Configure new provider: - + Use existing one: - - <html><head/><body><p>Now we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Bitmask -&gt; Create new account...'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html> + + Something has gone wrong. Please try again. - - Something has gone wrong. Please try again. + + The requested username is taken, choose another. - - Gathering configuration options for {0} + + Services by {0} - - The requested username is taken, choose another. + + Register a new user with {0} - - Services by {0} + + Bitmask Provider Setup - - Description of services offered by {0} + + Welcome to Bitmask - - Register a new user with {0} + + Choose a provider + + + + + Getting provider information. + + + + + About this provider + + + + + Bitmask is attempting to establish a secure connection with this provider for the first time. + + + + + Fetching provider credentials. + + + + + Do we trust these credentials? + + + + + Connecting to provider. msg - + TAP Driver - + Encrypted Internet uses VPN, which needs a TAP device installed and none has been found. This will ask for administrative privileges. - + TUN Driver - + Encrypted Internet uses VPN, which needs a kernel extension for a TUN device installed, and none has been found. This will ask for administrative privileges. - + Problem installing files - + Some of the files could not be copied. - + Bitmask needs to install the necessary drivers for Encrypted Internet to work. Would you like to proceed? - + Missing helper files - - Missing resolvconf framework - - - - + Missing Bitmask helpers @@ -1490,25 +1521,12 @@ Export canceled. msgstr - - Could not find <b>resolvconf</b> installed in your system. -Do you want to quit Bitmask now? - - - - - Encrypted Internet needs resolvconf installed to work properly. -Please use your package manager to install it. - - - - - + Some essential helper files are missing in your system. - + Reinstall your debian packages, or make sure you place them by hand. @@ -1516,17 +1534,17 @@ Please use your package manager to install it. self._eip_status - + {0} is restarting - + {0} could not be launched because you did not authenticate properly. - + {0} finished in an unexpected manner! -- cgit v1.2.3 From 4f4520d938f726b344e1a71949f83aa385d92acd Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 1 Sep 2014 18:31:36 -0300 Subject: Don't defer action to thread here. We already are running the methods in a thread from the backend. --- src/leap/bitmask/backend/components.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index 89f3c5a6..d4f6d176 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -452,20 +452,14 @@ class EIP(object): else: logger.debug('EIP: no errors') - def _do_stop(self, shutdown=False, restart=False): + def stop(self, shutdown=False, restart=False): """ - Stop the service. This is run in a thread to avoid blocking. + Stop the service. """ self._vpn.terminate(shutdown, restart) if IS_LINUX: self._wait_for_firewall_down() - def stop(self, shutdown=False, restart=False): - """ - Stop the service. - """ - return threads.deferToThread(self._do_stop, shutdown, restart) - def _wait_for_firewall_down(self): """ Wait for the firewall to come down. -- cgit v1.2.3 From 59ae590f4126b3e5635467e05b9985dabc80a2f9 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 1 Sep 2014 18:33:10 -0300 Subject: Move reactor import to the top. --- src/leap/bitmask/services/eip/vpnprocess.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index c7159a93..40aad257 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -50,8 +50,7 @@ from leap.common.check import leap_assert, leap_assert_type logger = logging.getLogger(__name__) vpnlog = logging.getLogger('leap.openvpn') -from twisted.internet import protocol -from twisted.internet import defer +from twisted.internet import defer, protocol, reactor from twisted.internet import error as internet_error from twisted.internet.task import LoopingCall @@ -157,10 +156,8 @@ class VPN(object): of a QObject containing the QSignals that we will pass along to the VPNManager. """ - from twisted.internet import reactor self._vpnproc = None self._pollers = [] - self._reactor = reactor self._signaler = kwargs['signaler'] self._openvpn_verb = flags.OPENVPN_VERBOSITY @@ -224,7 +221,7 @@ class VPN(object): for key, val in vpnproc.vpn_env.items(): env[key] = val - self._reactor.spawnProcess(vpnproc, cmd[0], cmd, env) + reactor.spawnProcess(vpnproc, cmd[0], cmd, env) self._vpnproc = vpnproc # add pollers for status and state @@ -300,7 +297,6 @@ class VPN(object): :param tries: counter of tries, used in recursion :type tries: int """ - from twisted.internet import reactor while tries < self.TERMINATE_MAXTRIES: if self._vpnproc.transport.pid is None: logger.debug("Process has been happily terminated.") @@ -351,7 +347,6 @@ class VPN(object): :param restart: whether this stop is part of a hard restart. :type restart: bool """ - from twisted.internet import reactor self._stop_pollers() # First we try to be polite and send a SIGTERM... @@ -424,8 +419,6 @@ class VPNManager(object): backend :type signaler: backend.Signaler """ - from twisted.internet import reactor - self._reactor = reactor self._tn = None self._signaler = signaler self._aborted = False @@ -602,7 +595,7 @@ class VPNManager(object): logger.debug('trying to connect to management') if not self.aborted and not self.is_connected(): self.connect_to_management(self._socket_host, self._socket_port) - self._reactor.callLater( + reactor.callLater( self.CONNECTION_RETRY_TIME, self.try_to_connect_to_management, retry + 1) -- cgit v1.2.3 From d65ecea2d6a943d6805284390e0361ae0ff00718 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 1 Sep 2014 19:03:26 -0300 Subject: Remove unused defers. Also, we no longer return defers for those actions. --- src/leap/bitmask/gui/wizard.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 0223c053..498e8501 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -96,11 +96,6 @@ class Wizard(QtGui.QWizard): # 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. - self._provider_select_defer = None - self._provider_setup_defer = None - self._connect_and_track(self.currentIdChanged, self._current_id_changed) @@ -479,8 +474,7 @@ class Wizard(QtGui.QWizard): self.button(QtGui.QWizard.BackButton).clearFocus() self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON) - self._provider_select_defer = self._backend.\ - provider_setup(provider=self._domain) + self._backend.provider_setup(provider=self._domain) @QtCore.Slot(bool) def _skip_provider_checks(self, skip): @@ -724,8 +718,7 @@ class Wizard(QtGui.QWizard): if not self._provider_setup_ok: self._reset_provider_setup() self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) - self._provider_setup_defer = self._backend.\ - provider_bootstrap(provider=self._domain) + self._backend.provider_bootstrap(provider=self._domain) if pageId == self.PRESENT_PROVIDER_PAGE: details = self._provider_details -- cgit v1.2.3 From de2f0e13a5a48e86b75eb54a56fe9f88b720193f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 3 Sep 2014 14:50:46 -0300 Subject: Better logging output for missing files and error. --- src/leap/bitmask/platform_init/initializers.py | 13 ++++++++----- src/leap/bitmask/services/eip/vpnprocess.py | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index 6c62734c..70d787dd 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -127,12 +127,15 @@ def check_missing(): complain_missing = True launcher = get_vpn_launcher() - missing_scripts = launcher.missing_updown_scripts - missing_other = launcher.missing_other_files + missing_scripts = launcher.missing_updown_scripts() + missing_other = launcher.missing_other_files() - logger.debug("MISSING OTHER: %s" % (str(missing_other()))) + if missing_scripts: + logger.warning("Missing scripts: %s" % (missing_scripts)) + if missing_other: + logger.warning("Missing other files: %s" % (missing_other)) - missing_some = missing_scripts() or missing_other() + missing_some = missing_scripts or missing_other if alert_missing and missing_some: msg = get_missing_helpers_dialog() ret = msg.exec_() @@ -168,7 +171,7 @@ def check_missing(): config.set_alert_missing_scripts(False) if complain_missing and missing_some: - missing = missing_scripts() + missing_other() + missing = missing_scripts + missing_other msg = _get_missing_complain_dialog(missing) ret = msg.exec_() diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index 40aad257..d41064ec 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -214,9 +214,10 @@ class VPN(object): # and abstract us away from anything else. try: cmd = vpnproc.getCommand() - except Exception: - logger.error("Error while getting vpn command...") + except Exception as e: + logger.error("Error while getting vpn command... {0!r}".format(e)) raise + env = os.environ for key, val in vpnproc.vpn_env.items(): env[key] = val -- cgit v1.2.3 From e6fae0977015919282971dbe8a00938415c1233b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 1 Sep 2014 19:03:46 -0300 Subject: Code cleanup and logging improvements. --- changes/code-and-logging-cleanup | 1 + src/leap/bitmask/gui/mainwindow.py | 18 ++++++++---------- src/leap/bitmask/gui/wizard.py | 5 +++-- src/leap/bitmask/services/eip/vpnprocess.py | 2 ++ src/leap/bitmask/services/mail/smtpbootstrapper.py | 2 ++ 5 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 changes/code-and-logging-cleanup diff --git a/changes/code-and-logging-cleanup b/changes/code-and-logging-cleanup new file mode 100644 index 00000000..3a381e68 --- /dev/null +++ b/changes/code-and-logging-cleanup @@ -0,0 +1 @@ +- Code cleanup and logging improvements. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 653ebc35..8127c1f6 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -206,6 +206,9 @@ class MainWindow(QtGui.QMainWindow): self._finally_quitting = False self._system_quit = False + # Used to differentiate between a real quit and a close to tray + self._close_to_tray = True + self._backend_connected_signals = [] self._backend_connect() @@ -229,9 +232,6 @@ class MainWindow(QtGui.QMainWindow): self.raise_window.connect(self._do_raise_mainwindow) - # Used to differentiate between real quits and close to tray - self._really_quit = False - self._systray = None # XXX separate actions into a different module. @@ -1144,7 +1144,7 @@ class MainWindow(QtGui.QMainWindow): return if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ - not self._really_quit: + self._close_to_tray: self._ensure_invisible() e.ignore() return @@ -1889,10 +1889,9 @@ class MainWindow(QtGui.QMainWindow): """ Stop services and cancel ongoing actions (if any). """ - logger.debug('About to quit, doing cleanup.') + logger.debug('Stopping services...') self._cancel_ongoing_defers() - self._services_being_stopped = set(('imap', 'eip')) imap_stopped = lambda: self._remove_service('imap') @@ -1921,9 +1920,10 @@ class MainWindow(QtGui.QMainWindow): if self._quitting: return - autostart.set_autostart(False) - self._quitting = True + self._close_to_tray = False + logger.debug('Quitting...') + autostart.set_autostart(False) # first thing to do quitting, hide the mainwindow and show tooltip. self.hide() @@ -1942,8 +1942,6 @@ class MainWindow(QtGui.QMainWindow): # Set this in case that the app is hidden QtGui.QApplication.setQuitOnLastWindowClosed(True) - self._really_quit = True - if not self._backend.online: self.final_quit() return diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 498e8501..8182228d 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -672,8 +672,9 @@ class Wizard(QtGui.QWizard): Loads the services that the provider provides into the UI for the user to enable or disable. """ - self.ui.grpServices.setTitle( - self.tr("Services by {0}").format(self._provider_details['domain'])) + title = self.tr("Services by {0}").format( + self._provider_details['domain']) + self.ui.grpServices.setTitle(title) services = get_supported(self._provider_details['services']) diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index d41064ec..8dc6021f 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -371,6 +371,8 @@ class VPN(object): logger.debug("Firewall down") else: logger.warning("Could not tear firewall down") + else: + logger.debug("VPN is not running.") def _start_pollers(self): """ diff --git a/src/leap/bitmask/services/mail/smtpbootstrapper.py b/src/leap/bitmask/services/mail/smtpbootstrapper.py index 3ef755e8..9dd61488 100644 --- a/src/leap/bitmask/services/mail/smtpbootstrapper.py +++ b/src/leap/bitmask/services/mail/smtpbootstrapper.py @@ -173,3 +173,5 @@ class SMTPBootstrapper(AbstractBootstrapper): logger.debug('Stopping SMTP service.') self._smtp_port.stopListening() self._smtp_service.doStop() + else: + logger.debug('SMTP service not running.') -- cgit v1.2.3 From b7b2c18b8d8ae09ac7f5ad86173380bf69409b80 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 5 Sep 2014 12:40:38 -0300 Subject: Use python2 explicitly to run bitmask-root. Closes #6048. --- changes/bug-6048_python2-bitmask-root | 1 + pkg/linux/bitmask-root | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/bug-6048_python2-bitmask-root diff --git a/changes/bug-6048_python2-bitmask-root b/changes/bug-6048_python2-bitmask-root new file mode 100644 index 00000000..038196b0 --- /dev/null +++ b/changes/bug-6048_python2-bitmask-root @@ -0,0 +1 @@ +- Use python2 to run bitmask-root to work fine on systems with python3 as default. Closes #6048. diff --git a/pkg/linux/bitmask-root b/pkg/linux/bitmask-root index c9034b0d..fa7fc92a 100755 --- a/pkg/linux/bitmask-root +++ b/pkg/linux/bitmask-root @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2 # -*- coding: utf-8 -*- # # Copyright (C) 2014 LEAP -- cgit v1.2.3 From dff4c53be63e5412fe4a8e69d26bf45bd949ec71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 5 Sep 2014 15:37:07 -0300 Subject: Send the token when querying the EIP cert --- changes/bug_use_token_for_eip | 1 + src/leap/bitmask/crypto/certs.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 changes/bug_use_token_for_eip diff --git a/changes/bug_use_token_for_eip b/changes/bug_use_token_for_eip new file mode 100644 index 00000000..b10368ad --- /dev/null +++ b/changes/bug_use_token_for_eip @@ -0,0 +1 @@ +- Properly send the token for querying the EIP certificate. Fixes #6060. \ No newline at end of file diff --git a/src/leap/bitmask/crypto/certs.py b/src/leap/bitmask/crypto/certs.py index 244decfd..c3ca4efb 100644 --- a/src/leap/bitmask/crypto/certs.py +++ b/src/leap/bitmask/crypto/certs.py @@ -46,19 +46,27 @@ def download_client_cert(provider_config, path, session): # again. srp_auth = SRPAuth(provider_config) session_id = srp_auth.get_session_id() + token = srp_auth.get_token() cookies = None - if session_id: + if session_id is not None: cookies = {"_session_id": session_id} cert_uri = "%s/%s/cert" % ( provider_config.get_api_uri(), provider_config.get_api_version()) logger.debug('getting cert from uri: %s' % cert_uri) + headers = {} + + # API v2 will only support token auth, but in v1 we can send both + if token is not None: + headers["Authorization"] = 'Token token="{0}"'.format(token) + res = session.get(cert_uri, verify=provider_config .get_ca_cert_path(), cookies=cookies, - timeout=REQUEST_TIMEOUT) + timeout=REQUEST_TIMEOUT, + headers=headers) res.raise_for_status() client_cert = res.content -- cgit v1.2.3 From 3d0708ad3e20aa8dddf6894b7536be3cd59cfbca Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Mon, 8 Sep 2014 14:22:29 -0500 Subject: Add email firewall --- changes/feature-6040-email-firewall | 1 + docs/man/bitmask-root.1.rst | 13 ++ pkg/linux/bitmask-root | 143 +++++++++++++++++++++- src/leap/bitmask/gui/mainwindow.py | 40 +----- src/leap/bitmask/services/eip/linuxvpnlauncher.py | 99 ++------------- src/leap/bitmask/services/mail/conductor.py | 19 +++ src/leap/bitmask/services/mail/emailfirewall.py | 115 +++++++++++++++++ src/leap/bitmask/util/privilege_policies.py | 98 +++++++++++++++ 8 files changed, 403 insertions(+), 125 deletions(-) create mode 100644 changes/feature-6040-email-firewall create mode 100644 src/leap/bitmask/services/mail/emailfirewall.py diff --git a/changes/feature-6040-email-firewall b/changes/feature-6040-email-firewall new file mode 100644 index 00000000..5ef70d28 --- /dev/null +++ b/changes/feature-6040-email-firewall @@ -0,0 +1 @@ +- Add email firewall blocking other users to access bitmask imap & smtp. Closes #6040 diff --git a/docs/man/bitmask-root.1.rst b/docs/man/bitmask-root.1.rst index c18cc4d6..dde303ae 100644 --- a/docs/man/bitmask-root.1.rst +++ b/docs/man/bitmask-root.1.rst @@ -49,6 +49,19 @@ firewall **stop** Stops the firewall. +**isup** Check if the firewall is up. + + +fw-email +--------- + +**start** UID Starts the email firewall. UID is the user name or unix + id that will have access to the email. + +**stop** Stops the email firewall. + +**isup** Check if the email firewall is up. + version -------- diff --git a/pkg/linux/bitmask-root b/pkg/linux/bitmask-root index fa7fc92a..ba262a2c 100755 --- a/pkg/linux/bitmask-root +++ b/pkg/linux/bitmask-root @@ -25,6 +25,8 @@ USAGE: bitmask-root firewall start [restart] GATEWAY1 GATEWAY2 ... bitmask-root openvpn stop bitmask-root openvpn start CONFIG1 CONFIG1 ... + bitmask-root fw-email stop + bitmask-root fw-email start uid All actions return exit code 0 for success, non-zero otherwise. @@ -55,6 +57,11 @@ NAMESERVER = "10.42.0.1" BITMASK_CHAIN = "bitmask" BITMASK_CHAIN_NAT_OUT = "bitmask" BITMASK_CHAIN_NAT_POST = "bitmask_postrouting" +BITMASK_CHAIN_EMAIL = "bitmask_email" +BITMASK_CHAIN_EMAIL_OUT = "bitmask_email_output" +LOCAL_INTERFACE = "lo" +IMAP_PORT = "1984" +SMTP_PORT = "2013" IP = "/bin/ip" IPTABLES = "/sbin/iptables" @@ -101,7 +108,8 @@ PARAM_FORMATS = { "^[a-zA-Z0-9_\.\@][a-zA-Z0-9_\-\.\@]*\$?$", s), # IEEE Std 1003.1-2001 "FILE": lambda s: os.path.isfile(s), "DIR": lambda s: os.path.isdir(os.path.split(s)[0]), - "UNIXSOCKET": lambda s: s == "unix" + "UNIXSOCKET": lambda s: s == "unix", + "UID": lambda s: re.match("^[a-zA-Z0-9]+$", s) } @@ -740,6 +748,119 @@ def firewall_stop(): "Please try `firewall stop` again.") +def fw_email_start(args): + """ + Bring up the email firewall. + + :param args: the user uid of the bitmask process + :type args: list + """ + # add custom chain "bitmask_email" to front of INPUT chain + if not ipv4_chain_exists(BITMASK_CHAIN_EMAIL): + ip4tables("--new-chain", BITMASK_CHAIN_EMAIL) + if not ipv6_chain_exists(BITMASK_CHAIN_EMAIL): + ip6tables("--new-chain", BITMASK_CHAIN_EMAIL) + iptables("--insert", "INPUT", "--jump", BITMASK_CHAIN_EMAIL) + + # add custom chain "bitmask_email_output" to front of OUTPUT chain + if not ipv4_chain_exists(BITMASK_CHAIN_EMAIL_OUT): + ip4tables("--new-chain", BITMASK_CHAIN_EMAIL_OUT) + if not ipv6_chain_exists(BITMASK_CHAIN_EMAIL_OUT): + ip6tables("--new-chain", BITMASK_CHAIN_EMAIL_OUT) + iptables("--insert", "OUTPUT", "--jump", BITMASK_CHAIN_EMAIL_OUT) + + # Disable the access to imap and smtp from outside + iptables("--append", BITMASK_CHAIN_EMAIL, + "--in-interface", LOCAL_INTERFACE, "--protocol", "tcp", + "--dport", IMAP_PORT, "--jump", "ACCEPT") + iptables("--append", BITMASK_CHAIN_EMAIL, + "--in-interface", LOCAL_INTERFACE, "--protocol", "tcp", + "--dport", SMTP_PORT, "--jump", "ACCEPT") + iptables("--append", BITMASK_CHAIN_EMAIL, + "--protocol", "tcp", "--dport", IMAP_PORT, "--jump", "REJECT") + iptables("--append", BITMASK_CHAIN_EMAIL, + "--protocol", "tcp", "--dport", SMTP_PORT, "--jump", "REJECT") + + if not args or not PARAM_FORMATS["UID"](args[0]): + raise Exception("No uid given") + uid = args[0] + + # Only the unix 'uid' have access to the email imap and smtp ports + iptables("--append", BITMASK_CHAIN_EMAIL_OUT, + "--out-interface", LOCAL_INTERFACE, + "--match", "owner", "--uid-owner", uid, "--protocol", "tcp", + "--dport", IMAP_PORT, "--jump", "ACCEPT") + iptables("--append", BITMASK_CHAIN_EMAIL_OUT, + "--out-interface", LOCAL_INTERFACE, + "--match", "owner", "--uid-owner", uid, "--protocol", "tcp", + "--dport", SMTP_PORT, "--jump", "ACCEPT") + iptables("--append", BITMASK_CHAIN_EMAIL_OUT, + "--out-interface", LOCAL_INTERFACE, + "--protocol", "tcp", "--dport", IMAP_PORT, "--jump", "REJECT") + iptables("--append", BITMASK_CHAIN_EMAIL_OUT, + "--out-interface", LOCAL_INTERFACE, + "--protocol", "tcp", "--dport", SMTP_PORT, "--jump", "REJECT") + + +def fw_email_stop(): + """ + Stop the email firewall. + """ + ok = True + + try: + iptables("--delete", "INPUT", "--jump", BITMASK_CHAIN_EMAIL, + throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to remove bitmask email firewall from INPUT " + "chain (maybe it is already removed?)", exc) + ok = False + + try: + iptables("--delete", "OUTPUT", "--jump", BITMASK_CHAIN_EMAIL_OUT, + throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to remove bitmask email firewall from OUTPUT " + "chain (maybe it is already removed?)", exc) + ok = False + + try: + ip4tables("--flush", BITMASK_CHAIN_EMAIL, throw=True) + ip4tables("--delete-chain", BITMASK_CHAIN_EMAIL, throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to flush and delete bitmask ipv4 email firewall " + "chain (maybe it is already destroyed?)", exc) + ok = False + + try: + ip6tables("--flush", BITMASK_CHAIN_EMAIL, throw=True) + ip6tables("--delete-chain", BITMASK_CHAIN_EMAIL, throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to flush and delete bitmask ipv6 email firewall " + "chain (maybe it is already destroyed?)", exc) + ok = False + + try: + ip4tables("--flush", BITMASK_CHAIN_EMAIL_OUT, throw=True) + ip4tables("--delete-chain", BITMASK_CHAIN_EMAIL_OUT, throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to flush and delete bitmask ipv4 email firewall " + "chain (maybe it is already destroyed?)", exc) + ok = False + + try: + ip6tables("--flush", BITMASK_CHAIN_EMAIL_OUT, throw=True) + ip6tables("--delete-chain", BITMASK_CHAIN_EMAIL_OUT, throw=True) + except subprocess.CalledProcessError as exc: + debug("INFO: not able to flush and delete bitmask ipv6 email firewall " + "chain (maybe it is already destroyed?)", exc) + ok = False + + if not (ok or ipv4_chain_exists or ipv6_chain_exists): + raise Exception("email firewall might still be left up. " + "Please try `fw-email stop` again.") + + # # MAIN # @@ -793,6 +914,26 @@ def main(): else: bail("INFO: bitmask firewall is down") + elif command == "fw-email_start": + try: + fw_email_start(args) + except Exception as ex: + if not is_restart: + fw_email_stop() + bail("ERROR: could not start email firewall", ex) + + elif command == "fw-email_stop": + try: + fw_email_stop() + except Exception as ex: + bail("ERROR: could not stop email firewall", ex) + + elif command == "fw-email_isup": + if ipv4_chain_exists(BITMASK_CHAIN_EMAIL): + log("%s: INFO: bitmask email firewall is up" % (SCRIPT,)) + else: + bail("INFO: bitmask email firewall is down") + else: bail("ERROR: No such command") else: diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 8127c1f6..9c5045ec 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -271,9 +271,7 @@ class MainWindow(QtGui.QMainWindow): # Services signals/slots connection self.new_updates.connect(self._react_to_new_updates) - # XXX should connect to mail_conductor.start_mail_service instead - self.soledad_ready.connect(self._start_smtp_bootstrapping) - self.soledad_ready.connect(self._start_imap_service) + self.soledad_ready.connect(self._start_mail_service) # ################################ end Qt Signals connection ######## init_platform() @@ -1563,37 +1561,12 @@ class MainWindow(QtGui.QMainWindow): self.soledad_ready.emit() ################################################################### - # Service control methods: smtp - - @QtCore.Slot() - def _start_smtp_bootstrapping(self): - """ - TRIGGERS: - self.soledad_ready - """ - if flags.OFFLINE is True: - logger.debug("not starting smtp in offline mode") - return - - if self._provides_mx_and_enabled(): - self._mail_conductor.start_smtp_service(download_if_needed=True) - - ################################################################### - # Service control methods: imap - + # Service control methods: mail @QtCore.Slot() - def _start_imap_service(self): - """ - TRIGGERS: - self.soledad_ready - """ - # 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) + def _start_mail_service(self): if self._provides_mx_and_enabled() or flags.OFFLINE: - self._mail_conductor.start_imap_service() - - # end service control methods (imap) + self._mail_conductor.start_mail_service(download_if_needed=True, + offline=flags.OFFLINE) ################################################################### # Service control methods: eip @@ -1902,8 +1875,7 @@ class MainWindow(QtGui.QMainWindow): self._leap_signaler.eip_stopped.connect(eip_stopped) logger.debug('Stopping mail services') - self._backend.imap_stop_service() - self._backend.smtp_stop_service() + self._mail_conductor.stop_mail_services() if self._logged_user is not None: logger.debug("Doing logout") diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py index b6e47f25..a3ab408b 100644 --- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -20,17 +20,15 @@ Linux VPN launcher implementation. import commands import logging import os -import subprocess import sys -import time from leap.bitmask.config import flags from leap.bitmask.util.privilege_policies import LinuxPolicyChecker -from leap.common.files import which +from leap.bitmask.util.privilege_policies import NoPolkitAuthAgentAvailable +from leap.bitmask.util.privilege_policies import NoPkexecAvailable from leap.bitmask.services.eip.vpnlauncher import VPNLauncher from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException from leap.bitmask.util import get_path_prefix, force_eval -from leap.common.check import leap_assert from leap.bitmask.util import first logger = logging.getLogger(__name__) @@ -46,66 +44,11 @@ class EIPNoPkexecAvailable(VPNLauncherException): pass -def _is_pkexec_in_system(): - """ - Checks the existence of the pkexec binary in system. - """ - pkexec_path = which('pkexec') - if len(pkexec_path) == 0: - return False - return True - - -def _is_auth_agent_running(): - """ - Checks if a polkit daemon is running. - - :return: True if it's running, False if it's not. - :rtype: boolean - """ - # Note that gnome-shell does not uses a separate process for the - # polkit-agent, it uses a polkit-agent within its own process so we can't - # ps-grep a polkit process, we can ps-grep gnome-shell itself. - - # the [x] thing is to avoid grep match itself - polkit_options = [ - 'ps aux | grep "polkit-[g]nome-authentication-agent-1"', - 'ps aux | grep "polkit-[k]de-authentication-agent-1"', - 'ps aux | grep "polkit-[m]ate-authentication-agent-1"', - 'ps aux | grep "[l]xpolkit"', - 'ps aux | grep "[g]nome-shell"', - 'ps aux | grep "[f]ingerprint-polkit-agent"', - ] - is_running = [commands.getoutput(cmd) for cmd in polkit_options] - - return any(is_running) - - -def _try_to_launch_agent(): - """ - Tries to launch a polkit daemon. - """ - env = None - if flags.STANDALONE: - env = {"PYTHONPATH": os.path.abspath('../../../../lib/')} - try: - # We need to quote the command because subprocess call - # will do "sh -c 'foo'", so if we do not quoute it we'll end - # up with a invocation to the python interpreter. And that - # is bad. - logger.debug("Trying to launch polkit agent") - subprocess.call(["python -m leap.bitmask.util.polkit_agent"], - shell=True, env=env) - except Exception as exc: - logger.exception(exc) - - SYSTEM_CONFIG = "/etc/leap" leapfile = lambda f: "%s/%s" % (SYSTEM_CONFIG, f) class LinuxVPNLauncher(VPNLauncher): - PKEXEC_BIN = 'pkexec' # The following classes depend on force_eval to be called against # the classes, to get the evaluation of the standalone flag on runtine. @@ -129,36 +72,6 @@ class LinuxVPNLauncher(VPNLauncher): OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH) - @classmethod - def maybe_pkexec(kls): - """ - Checks whether pkexec is available in the system, and - returns the path if found. - - Might raise: - EIPNoPkexecAvailable, - EIPNoPolkitAuthAgentAvailable. - - :returns: a list of the paths where pkexec is to be found - :rtype: list - """ - if _is_pkexec_in_system(): - if not _is_auth_agent_running(): - _try_to_launch_agent() - time.sleep(2) - if _is_auth_agent_running(): - pkexec_possibilities = which(kls.PKEXEC_BIN) - leap_assert(len(pkexec_possibilities) > 0, - "We couldn't find pkexec") - return pkexec_possibilities - else: - logger.warning("No polkit auth agent found. pkexec " + - "will use its own auth agent.") - raise EIPNoPolkitAuthAgentAvailable() - else: - logger.warning("System has no pkexec") - raise EIPNoPkexecAvailable() - @classmethod def get_vpn_command(kls, eipconfig, providerconfig, socket_host, socket_port="unix", openvpn_verb=1): @@ -194,7 +107,13 @@ class LinuxVPNLauncher(VPNLauncher): command.insert(1, "openvpn") command.insert(2, "start") - pkexec = kls.maybe_pkexec() + policyChecker = LinuxPolicyChecker() + try: + pkexec = policyChecker.maybe_pkexec() + except NoPolkitAuthAgentAvailable: + raise EIPNoPolkitAuthAgentAvailable() + except NoPkexecAvailable: + raise EIPNoPkexecAvailable() if pkexec: command.insert(0, first(pkexec)) diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index 5e85368f..416aff34 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -22,6 +22,7 @@ import logging from leap.bitmask.config import flags from leap.bitmask.gui import statemachines from leap.bitmask.services.mail import connection as mail_connection +from leap.bitmask.services.mail.emailfirewall import get_email_firewall from leap.common.events import events_pb2 as leap_events from leap.common.events import register as leap_register @@ -211,6 +212,11 @@ class MailConductor(IMAPControl, SMTPControl): self._mail_connection = mail_connection.MailConnection() self._userid = None + try: + self._firewall = get_email_firewall() + except NotImplementedError: + self._firewall = None + logger.info("Email firewall is not implemented in this platform") @property def userid(self): @@ -247,12 +253,25 @@ class MailConductor(IMAPControl, SMTPControl): self._smtp_machine = smtp self._smtp_machine.start() + def start_mail_service(self, download_if_needed=False, offline=False): + """ + Start the IMAP and SMTP servcies. + """ + if self._firewall is not None: + self._firewall.start() + if not offline: + logger.debug("not starting smtp in offline mode") + self.start_smtp_service(download_if_needed=download_if_needed) + self.start_imap_service() + def stop_mail_services(self): """ Stop the IMAP and SMTP services. """ self.stop_imap_service() self.stop_smtp_service() + if self._firewall is not None: + self._firewall.stop() def connect_mail_signals(self, widget): """ diff --git a/src/leap/bitmask/services/mail/emailfirewall.py b/src/leap/bitmask/services/mail/emailfirewall.py new file mode 100644 index 00000000..2cd2ec31 --- /dev/null +++ b/src/leap/bitmask/services/mail/emailfirewall.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# emailfirewall.py +# Copyright (C) 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 . +""" +Email firewall implementation. +""" + +import os +import subprocess + +from abc import ABCMeta, abstractmethod + +from leap.bitmask.config import flags +from leap.bitmask.platform_init import IS_LINUX +from leap.bitmask.util import first, force_eval +from leap.bitmask.util.privilege_policies import LinuxPolicyChecker +from leap.common.check import leap_assert + + +def get_email_firewall(): + """ + Return the email firewall handler for the current platform. + """ + if not (IS_LINUX): + error_msg = "Email firewall not implemented for this platform." + raise NotImplementedError(error_msg) + + firewall = None + if IS_LINUX: + firewall = LinuxEmailFirewall + + leap_assert(firewall is not None) + + return firewall() + + +class EmailFirewall(object): + """ + Abstract email firwall class + """ + __metaclass__ = ABCMeta + + @abstractmethod + def start(self): + """ + Start email firewall + """ + return False + + @abstractmethod + def stop(self): + """ + Stop email firewall + """ + return False + + +class EmailFirewallException(Exception): + pass + + +class LinuxEmailFirewall(EmailFirewall): + + class BITMASK_ROOT(object): + def __call__(self): + return ("/usr/local/sbin/bitmask-root" if flags.STANDALONE else + "/usr/sbin/bitmask-root") + + def start(self): + uid = str(os.getuid()) + return True if self._run(["start", uid]) is 0 else False + + def stop(self): + return True if self._run(["stop"]) is 0 else False + + def _run(self, cmd): + """ + Run an email firewall command with bitmask-root + + Might raise: + NoPkexecAvailable, + NoPolkitAuthAgentAvailable, + + :param cmd: command to send to bitmask-root fw-email + :type cmd: [str] + :returns: exit code of bitmask-root + :rtype: int + """ + command = [] + + policyChecker = LinuxPolicyChecker() + pkexec = policyChecker.maybe_pkexec() + if pkexec: + command.append(first(pkexec)) + + command.append(force_eval(self.BITMASK_ROOT)) + command.append("fw-email") + command += cmd + + # XXX: will be nice to use twisted ProcessProtocol instead of + # subprocess to avoid blocking until it finish + return subprocess.call(command) diff --git a/src/leap/bitmask/util/privilege_policies.py b/src/leap/bitmask/util/privilege_policies.py index f894d73b..2016e67b 100644 --- a/src/leap/bitmask/util/privilege_policies.py +++ b/src/leap/bitmask/util/privilege_policies.py @@ -18,17 +18,30 @@ Helpers to determine if the needed policies for privilege escalation are operative under this client run. """ +import commands import logging import os +import subprocess import platform +import time from abc import ABCMeta, abstractmethod from leap.bitmask.config import flags +from leap.common.check import leap_assert +from leap.common.files import which logger = logging.getLogger(__name__) +class NoPolkitAuthAgentAvailable(Exception): + pass + + +class NoPkexecAvailable(Exception): + pass + + def is_missing_policy_permissions(): """ Returns True if we do not have implemented a policy checker for this @@ -75,6 +88,7 @@ class LinuxPolicyChecker(PolicyChecker): "se.leap.bitmask.policy") LINUX_POLKIT_FILE_BUNDLE = ("/usr/share/polkit-1/actions/" "se.leap.bitmask.bundle.policy") + PKEXEC_BIN = 'pkexec' @classmethod def get_polkit_path(self): @@ -97,3 +111,87 @@ class LinuxPolicyChecker(PolicyChecker): """ path = self.get_polkit_path() return not os.path.isfile(path) + + @classmethod + def maybe_pkexec(self): + """ + Checks whether pkexec is available in the system, and + returns the path if found. + + Might raise: + NoPkexecAvailable, + NoPolkitAuthAgentAvailable. + + :returns: a list of the paths where pkexec is to be found + :rtype: list + """ + if self._is_pkexec_in_system(): + if not self.is_up(): + self.launch() + time.sleep(2) + if self.is_up(): + pkexec_possibilities = which(self.PKEXEC_BIN) + leap_assert(len(pkexec_possibilities) > 0, + "We couldn't find pkexec") + return pkexec_possibilities + else: + logger.warning("No polkit auth agent found. pkexec " + + "will use its own auth agent.") + raise NoPolkitAuthAgentAvailable() + else: + logger.warning("System has no pkexec") + raise NoPkexecAvailable() + + @classmethod + def launch(self): + """ + Tries to launch policykit + """ + env = None + if flags.STANDALONE: + env = {"PYTHONPATH": os.path.abspath('../../../../lib/')} + try: + # We need to quote the command because subprocess call + # will do "sh -c 'foo'", so if we do not quoute it we'll end + # up with a invocation to the python interpreter. And that + # is bad. + logger.debug("Trying to launch polkit agent") + subprocess.call(["python -m leap.bitmask.util.polkit_agent"], + shell=True, env=env) + except Exception as exc: + logger.exception(exc) + + @classmethod + def is_up(self): + """ + Checks if a polkit daemon is running. + + :return: True if it's running, False if it's not. + :rtype: boolean + """ + # Note that gnome-shell does not uses a separate process for the + # polkit-agent, it uses a polkit-agent within its own process so we + # can't ps-grep a polkit process, we can ps-grep gnome-shell itself. + + # the [x] thing is to avoid grep match itself + polkit_options = [ + 'ps aux | grep "polkit-[g]nome-authentication-agent-1"', + 'ps aux | grep "polkit-[k]de-authentication-agent-1"', + 'ps aux | grep "polkit-[m]ate-authentication-agent-1"', + 'ps aux | grep "[l]xpolkit"', + 'ps aux | grep "[g]nome-shell"', + 'ps aux | grep "[f]ingerprint-polkit-agent"', + ] + is_running = [commands.getoutput(cmd) for cmd in polkit_options] + + return any(is_running) + + @classmethod + def _is_pkexec_in_system(self): + """ + Checks the existence of the pkexec binary in system. + """ + pkexec_path = which('pkexec') + if len(pkexec_path) == 0: + return False + return True -- cgit v1.2.3 From f9ed736e41aa63b60925802fad021fc387dbc303 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Fri, 12 Sep 2014 13:30:42 -0500 Subject: Initializers needs to use PolicyChecker to get pkexec in linux --- src/leap/bitmask/platform_init/initializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index 70d787dd..1d6bb1d0 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -29,9 +29,9 @@ from PySide import QtGui, QtCore from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.services.eip import get_vpn_launcher -from leap.bitmask.services.eip.linuxvpnlauncher import LinuxVPNLauncher from leap.bitmask.services.eip.darwinvpnlauncher import DarwinVPNLauncher from leap.bitmask.util import first +from leap.bitmask.util.privilege_policies import LinuxPolicyChecker logger = logging.getLogger(__name__) @@ -445,7 +445,6 @@ def _linux_install_missing_scripts(badexec, notfound): success = False installer_path = os.path.abspath( os.path.join(os.getcwd(), "apps", "eip", "files")) - launcher = LinuxVPNLauncher install_helper = "leap-install-helper.sh" install_helper_path = os.path.join(installer_path, install_helper) @@ -456,7 +455,8 @@ def _linux_install_missing_scripts(badexec, notfound): if os.path.isdir(installer_path): try: - pkexec = first(launcher.maybe_pkexec()) + policyChecker = LinuxPolicyChecker() + pkexec = first(policyChecker.maybe_pkexec()) cmdline = ["%s %s %s" % ( pkexec, install_helper_path, install_opts)] -- cgit v1.2.3 From 719c472f23490dfe039327743f4553f600c799a9 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 15 Sep 2014 17:52:57 -0300 Subject: Improve support for RTL languages. * Update transifex resource name. * Use RightToLeft layout for Arabic language. * Use better names and comments on i18n section. * Use unicode to initialize widgets with text that otherwise (str) will fail when Arabic (and most likely any other language with non-ascii characters) is used. Closes #5289, #6033. --- .tx/config | 2 +- src/leap/bitmask/frontend_app.py | 27 ++++++++++++++++++--------- src/leap/bitmask/gui/eip_status.py | 2 +- src/leap/bitmask/gui/mainwindow.py | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/.tx/config b/.tx/config index 31ea5b1c..c52bc2d7 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,7 @@ [main] host = https://www.transifex.com -[bitmask.bitmask] +[bitmask.bitmask_client] file_filter = data/translations/.ts source_file = data/ts/en_US.ts diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 5ea89fc9..909005f0 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -76,15 +76,24 @@ def run_frontend(options, flags_dict, backend_pid): qApp = QtGui.QApplication(sys.argv) - # To test: - # $ LANG=es ./app.py - locale = QtCore.QLocale.system().name() - qtTranslator = QtCore.QTranslator() - if qtTranslator.load("qt_%s" % locale, ":/translations"): - qApp.installTranslator(qtTranslator) - appTranslator = QtCore.QTranslator() - if appTranslator.load("%s.qm" % locale[:2], ":/translations"): - qApp.installTranslator(appTranslator) + # To test the app in other language you can do: + # shell> LANG=es bitmask + # or in some rare case if the code above didn't work: + # shell> LC_ALL=es LANG=es bitmask + locale = QtCore.QLocale.system().name() # en_US, es_AR, ar_SA, etc + locale_short = locale[:2] # en, es, ar, etc + rtl_languages = ('ar', ) # right now tested on 'arabic' only. + + systemQtTranslator = QtCore.QTranslator() + if systemQtTranslator.load("qt_%s" % locale, ":/translations"): + qApp.installTranslator(systemQtTranslator) + + bitmaskQtTranslator = QtCore.QTranslator() + if bitmaskQtTranslator.load("%s.qm" % locale_short, ":/translations"): + qApp.installTranslator(bitmaskQtTranslator) + + if locale_short in rtl_languages: + qApp.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) # Needed for initializing qsettings it will write # .config/leap/leap.conf top level app settings in a platform diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 1c167335..a5cd03d3 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -97,7 +97,7 @@ class EIPStatusWidget(QtGui.QWidget): # Action for the systray self._eip_disabled_action = QtGui.QAction( - "{0} is {1}".format(self._service_name, self.tr("disabled")), self) + u"{0} is {1}".format(self._service_name, self.tr("disabled")), self) def connect_backend_signals(self): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 9c5045ec..4e11c979 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -934,7 +934,7 @@ class MainWindow(QtGui.QMainWindow): systrayMenu.addAction(self._action_visible) systrayMenu.addSeparator() - eip_status_label = "{0}: {1}".format( + eip_status_label = u"{0}: {1}".format( self._eip_conductor.eip_name, self.tr("OFF")) self._eip_menu = eip_menu = systrayMenu.addMenu(eip_status_label) eip_menu.addAction(self._action_eip_startstop) -- cgit v1.2.3 From 0feb84c61b1f8efe9196af915e7500e97fa6b314 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 16 Sep 2014 18:17:59 -0300 Subject: Hide AKM menu and disable the qt connection. Hide the Advaneced Key Management menu from the ui file and comment out the connection between the triggered action and the method that shows the AKM window. Closes #6087. --- changes/feature-6087_remove-AKM-menu | 2 ++ src/leap/bitmask/gui/mainwindow.py | 5 +++-- src/leap/bitmask/gui/ui/mainwindow.ui | 9 ++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 changes/feature-6087_remove-AKM-menu diff --git a/changes/feature-6087_remove-AKM-menu b/changes/feature-6087_remove-AKM-menu new file mode 100644 index 00000000..9326ca47 --- /dev/null +++ b/changes/feature-6087_remove-AKM-menu @@ -0,0 +1,2 @@ +- Remove the Advanced Key Management since we don't support stable mail yet. + Closes #6087. diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 4e11c979..916e7c1f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -224,8 +224,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.action_create_new_account.triggered.connect( self._on_provider_changed) - self.ui.action_advanced_key_management.triggered.connect( - self._show_AKM) + # Action item hidden since we don't provide stable mail yet. + # self.ui.action_advanced_key_management.triggered.connect( + # self._show_AKM) if IS_MAC: self.ui.menuFile.menuAction().setText(self.tr("File")) diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 92c13d15..f7570ee6 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -75,7 +75,7 @@ 0 0 524 - 540 + 549 @@ -306,7 +306,7 @@ 0 0 524 - 25 + 21 @@ -378,11 +378,14 @@ - true + false Advanced Key Management + + false + -- cgit v1.2.3 From f66493426a7d0839801c81089ade6511efa1be3a Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 18 Sep 2014 13:09:07 -0500 Subject: Use wheels! yeah! No more infinite time to re-create a virtualenv. --- Makefile | 14 ++++++++++++++ pkg/requirements-dev.pip | 10 +++++++--- pkg/requirements.pip | 7 ++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 0008cb39..bbeebc36 100644 --- a/Makefile +++ b/Makefile @@ -95,5 +95,19 @@ resource_graph: ./pkg/scripts/monitor_resource.zsh `pgrep bitmask` $(RESOURCE_TIME) display bitmask-resources.png +get_wheels: + pip install --upgrade setuptools + pip install --upgrade pip + pip install wheel + +gather_wheels: + pip wheel --wheel-dir=../wheelhouse pyzmq --build-option "--zmq=bundled" + # because fuck u1db externals, that's why... + pip wheel --wheel-dir=../wheelhouse --allow-external dirspec --allow-unverified dirspec --allow-external u1db --allow-unverified u1db -r pkg/requirements.pip + +install_wheel: + # if it's the first time, you'll need to get_wheels first + pip install --pre --use-wheel --no-index --find-links=../wheelhouse -r pkg/requirements.pip + clean : $(RM) $(COMPILED_UI) $(COMPILED_RESOURCES) $(COMPILED_UI:.py=.pyc) $(COMPILED_RESOURCES:.py=.pyc) diff --git a/pkg/requirements-dev.pip b/pkg/requirements-dev.pip index 8b5a8d85..799376d2 100644 --- a/pkg/requirements-dev.pip +++ b/pkg/requirements-dev.pip @@ -10,8 +10,12 @@ # NOTE: you have to run pip install -r pkg/requirements.pip for pip # to install it. (do it after python setup.py develop and it # will only install this) - +# +wheel sphinx +ipdb --e git+https://github.com/leapcode/leap_pycommon.git@develop#egg=leap.common --e git+https://github.com/leapcode/soledad.git@develop#egg=leap.soledad +# in case you want to install a package from a git source, you can use this: +# Useful to test pre-release branches together. +#-e git+https://github.com/leapcode/leap_pycommon.git@develop#egg=leap.common +#-e git+https://github.com/leapcode/soledad.git@develop#egg=leap.soledad diff --git a/pkg/requirements.pip b/pkg/requirements.pip index bf05aa28..9f49bf03 100644 --- a/pkg/requirements.pip +++ b/pkg/requirements.pip @@ -9,7 +9,10 @@ argparse requests>=1.1.0 srp>=1.0.2 pyopenssl -python-dateutil + +# This won't be needed after we refactor leap.common.events +# to use zmq. +python-dateutil==1.4 # See https://leap.se/code/issues/6099 psutil @@ -19,6 +22,8 @@ python-daemon # this should not be needed for Windows. keyring zope.proxy +# You will want to install this bundled if you don't have sodium in your system: +# pip install pyzmq --install-option="--zmq=bundled" pyzmq leap.common>=0.3.7 -- cgit v1.2.3 From 8cd1fb9221fda7d8a516cf5accaac36ef2a9f656 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Fri, 19 Sep 2014 11:59:58 -0500 Subject: bump version because we've updated it with mail fw. --- pkg/linux/bitmask-root | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/linux/bitmask-root b/pkg/linux/bitmask-root index ba262a2c..767dcc38 100755 --- a/pkg/linux/bitmask-root +++ b/pkg/linux/bitmask-root @@ -51,7 +51,7 @@ cmdcheck = subprocess.check_output # CONSTANTS # -VERSION = "2" +VERSION = "3" SCRIPT = "bitmask-root" NAMESERVER = "10.42.0.1" BITMASK_CHAIN = "bitmask" -- cgit v1.2.3 From c7304e54e40cd9151e6d00a8441aaf48b68c9bcc Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 3 Sep 2014 15:50:08 -0700 Subject: single pref win: move eip preferences to new combined preference window. --- Makefile | 16 +- data/resources/flags.qrc | 1 + src/leap/bitmask/gui/mainwindow.py | 38 +- src/leap/bitmask/gui/preferences_account_page.py | 165 ++++++++ src/leap/bitmask/gui/preferences_email_page.py | 38 ++ src/leap/bitmask/gui/preferences_vpn_page.py | 150 ++++++++ src/leap/bitmask/gui/preferenceswindow.py | 419 +++------------------ src/leap/bitmask/gui/ui/eippreferences.ui | 102 ----- src/leap/bitmask/gui/ui/mainwindow.ui | 8 +- src/leap/bitmask/gui/ui/preferences.ui | 234 +++++------- .../bitmask/gui/ui/preferences_account_page.ui | 95 +++++ src/leap/bitmask/gui/ui/preferences_email_page.ui | 32 ++ src/leap/bitmask/gui/ui/preferences_vpn_page.ui | 89 +++++ src/leap/bitmask/services/eip/eipconfig.py | 43 ++- 14 files changed, 760 insertions(+), 670 deletions(-) create mode 100644 src/leap/bitmask/gui/preferences_account_page.py create mode 100644 src/leap/bitmask/gui/preferences_email_page.py create mode 100644 src/leap/bitmask/gui/preferences_vpn_page.py delete mode 100644 src/leap/bitmask/gui/ui/eippreferences.ui create mode 100644 src/leap/bitmask/gui/ui/preferences_account_page.ui create mode 100644 src/leap/bitmask/gui/ui/preferences_email_page.ui create mode 100644 src/leap/bitmask/gui/ui/preferences_vpn_page.ui diff --git a/Makefile b/Makefile index bbeebc36..e7173c80 100644 --- a/Makefile +++ b/Makefile @@ -19,9 +19,19 @@ TRANSLAT_DIR = data/translations #Project file, used for translations PROJFILE = data/bitmask.pro -#UI files to compile -UI_FILES = loggerwindow.ui mainwindow.ui wizard.ui login.ui preferences.ui eip_status.ui mail_status.ui eippreferences.ui advanced_key_management.ui -#Qt resource files to compile +# UI files to compile +UI_FILES = \ + loggerwindow.ui \ + wizard.ui \ + mainwindow.ui login.ui eip_status.ui mail_status.ui \ + preferences.ui \ + preferences_account_page.ui \ + preferences_vpn_page.ui \ + preferences_email_page.ui \ + password_change.ui \ + advanced_key_management.ui + +# Qt resource files to compile RESOURCES = icons.qrc flags.qrc locale.qrc loggerwindow.qrc #pyuic4 and pyrcc4 binaries diff --git a/data/resources/flags.qrc b/data/resources/flags.qrc index 8bdc9c4c..aeecc54f 100644 --- a/data/resources/flags.qrc +++ b/data/resources/flags.qrc @@ -58,6 +58,7 @@ ../images/countries/us.png ../images/countries/ve.png ../images/countries/vn.png + ../images/countries/xx.png ../images/countries/za.png \ No newline at end of file diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 916e7c1f..243fe117 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -37,7 +37,6 @@ from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement -from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow from leap.bitmask.gui.eip_status import EIPStatusWidget from leap.bitmask.gui.loggerwindow import LoggerWindow from leap.bitmask.gui.login import LoginWidget @@ -97,6 +96,9 @@ class MainWindow(QtGui.QMainWindow): # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 3000 # in milliseconds + # Preferences window + preferences = None + def __init__(self, start_hidden=False, backend_pid=None): """ Constructor for the client main window @@ -213,8 +215,6 @@ class MainWindow(QtGui.QMainWindow): self._backend_connect() self.ui.action_preferences.triggered.connect(self._show_preferences) - self.ui.action_eip_preferences.triggered.connect( - self._show_eip_preferences) self.ui.action_about_leap.triggered.connect(self._about) self.ui.action_quit.triggered.connect(self.quit) self.ui.action_wizard.triggered.connect(self._launch_wizard) @@ -247,7 +247,6 @@ class MainWindow(QtGui.QMainWindow): # disable buttons for now, may come back later. # self.ui.btnPreferences.clicked.connect(self._show_preferences) - # self.ui.btnEIPPreferences.clicked.connect(self._show_eip_preferences) self._enabled_services = [] self._ui_mx_visible = True @@ -601,16 +600,13 @@ class MainWindow(QtGui.QMainWindow): """ user = self._logged_user 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'] - preferences = PreferencesWindow(self, user, domain, self._backend, - self._soledad_started, mx_provided, - self._leap_signaler) - - self.soledad_ready.connect(preferences.set_soledad_ready) - preferences.show() - preferences.preferences_saved.connect(self._update_eip_enabled_status) + if self.preferences is not None: + self.preferences.close() + self.preferences = PreferencesWindow(self, user, domain, + self._backend, + self._soledad_started, + self._leap_signaler) + self.preferences.show() @QtCore.Slot() def _update_eip_enabled_status(self): @@ -718,20 +714,6 @@ class MainWindow(QtGui.QMainWindow): """ self._eip_status.missing_helpers = True - @QtCore.Slot() - def _show_eip_preferences(self): - """ - TRIGGERS: - self.ui.btnEIPPreferences.clicked - self.ui.action_eip_preferences (disabled for now) - - Display the EIP preferences window. - """ - domain = self._providers.get_selected_provider() - pref = EIPPreferencesWindow(self, domain, - self._backend, self._leap_signaler) - pref.show() - # # updates # diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py new file mode 100644 index 00000000..9cc94482 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . +""" +Widget for "account" preferences +""" +import logging + +from functools import partial + +from PySide import QtCore, QtGui +from ui_preferences_account_page import Ui_PreferencesAccountPage + +logger = logging.getLogger(__name__) + +class PreferencesAccountPage(QtGui.QWidget): + """ + + """ + + def __init__(self, parent): + """ + """ + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_PreferencesAccountPage() + self.ui.setupUi(self) + self.show() + + self._selected_services = set() + #self._leap_signaler.prov_get_supported_services.connect(self._load_services) + + @QtCore.Slot() + def set_soledad_ready(self): + """ + TRIGGERS: + parent.soledad_ready + + It notifies when the soledad object as ready to use. + """ + #self.ui.lblPasswordChangeStatus.setVisible(False) + #self.ui.gbPasswordChange.setEnabled(True) + + @QtCore.Slot(str, int) + def _service_selection_changed(self, service, state): + """ + TRIGGERS: + 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) + + @QtCore.Slot(str) + def _populate_services(self, domain): + """ + TRIGGERS: + self.ui.cbProvidersServices.currentIndexChanged[unicode] + + Fill the services list with the selected provider's services. + + :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) + + if not domain: + 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) + + self._backend.provider_get_supported_services(domain=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 + 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_label = get_service_display_name(service) + checkbox.setText(service_label) + + 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,)) + + @QtCore.Slot(str) + def _save_enabled_services(self, provider): + """ + TRIGGERS: + self.ui.pbSaveServices.clicked + + Saves the new enabled services 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) + self.preferences_saved.emit() diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py new file mode 100644 index 00000000..08ff5463 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . +""" +Widget for "email" preferences +""" +import logging + +from PySide import QtCore, QtGui +from ui_preferences_email_page import Ui_PreferencesEmailPage + +logger = logging.getLogger(__name__) + +class PreferencesEmailPage(QtGui.QWidget): + """ + + """ + + def __init__(self, parent): + """ + """ + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_PreferencesEmailPage() + self.ui.setupUi(self) + self.show() + diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py new file mode 100644 index 00000000..ba1366e4 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . +""" +Widget for "vpn" preferences +""" + +from PySide import QtCore, QtGui +from ui_preferences_vpn_page import Ui_PreferencesVpnPage + +from leap.bitmask.config.leapsettings import LeapSettings + + +class PreferencesVpnPage(QtGui.QWidget): + """ + Page in the preferences window that shows VPN settings + """ + + def __init__(self, parent, domain, backend, leap_signaler): + """ + :param parent: parent object of the EIPPreferencesWindow. + :type parent: QWidget + + :param domain: the selected by default domain. + :type domain: unicode + + :param backend: Backend being used + :type backend: Backend + """ + QtGui.QWidget.__init__(self, parent) + self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") + + self._settings = LeapSettings() + self._leap_signaler = leap_signaler + self._backend = backend + + # Load UI + self.ui = Ui_PreferencesVpnPage() + self.ui.setupUi(self) + self.ui.flash_label.setVisible(False) + + # Connections + self.ui.gateways_list.clicked.connect(self._save_selected_gateway) + + self._domain = domain + self._backend_connect() + self._backend.eip_get_gateways_list(domain=domain) + + def _flash_error(self, message): + """ + Sets string for the flash message. + + :param message: the text to be displayed + :type message: str + """ + message = "%s" % (message,) + self.ui.flash_label.setVisible(True) + self.ui.flash_label.setText(message) + + # def _flash_success(self, message): + # """ + # Sets string for the flash message. + # + # :param message: the text to be displayed + # :type message: str + # """ + # message = "%s" % (message,) + # self.ui.flash_label.setVisible(True) + # self.ui.flash_label.setText(message) + + @QtCore.Slot(str) + def _save_selected_gateway(self, index): + """ + TRIGGERS: + self.ui.gateways_list.clicked + + Saves the new gateway setting to the configuration file. + + :param index: the current index of the selection. + :type current_item: QModelIndex + """ + item = self.ui.gateways_list.currentItem() + + if item.text() == self.AUTOMATIC_GATEWAY_LABEL: + gateway = self._settings.GATEWAY_AUTOMATIC + else: + gateway = item.data(QtCore.Qt.UserRole) + self._settings.set_selected_gateway(self._domain, gateway) + self._backend.settings_set_selected_gateway(provider=self._domain, + gateway=gateway) + + @QtCore.Slot(list) + def _update_gateways_list(self, gateways): + """ + TRIGGERS: + Signaler.eip_get_gateways_list + + :param gateways: a list of gateways + :type gateways: list of unicode + + Add the available gateways and select the one stored in + configuration file. + """ + self.ui.gateways_list.clear() + self.ui.gateways_list.addItem(self.AUTOMATIC_GATEWAY_LABEL) + + selected_gateway = self._settings.get_selected_gateway( + self._domain) + + index = 0 + for idx, (gw_name, gw_ip, gw_country) in enumerate(gateways): + gateway_text = "{0} ({1})".format(gw_name, gw_ip) + item = QtGui.QListWidgetItem(self.ui.gateways_list) + item.setText(gateway_text) + item.setIcon(QtGui.QIcon( + ":/images/countries/%s.png" % (gw_country.lower(),))) + item.setData(QtCore.Qt.UserRole, gw_ip) + if gw_ip == selected_gateway: + index = idx + 1 + self.ui.gateways_list.setCurrentRow(index) + + @QtCore.Slot() + def _gateways_list_error(self): + """ + TRIGGERS: + Signaler.eip_get_gateways_list_error + + An error has occurred retrieving the gateway list + so we inform the user. + """ + self._flash_error( + self.tr("Error loading configuration file.")) + self.ui.gateways_list.setEnabled(False) + + def _backend_connect(self): + sig = self._leap_signaler + sig.eip_get_gateways_list.connect(self._update_gateways_list) + sig.eip_get_gateways_list_error.connect(self._gateways_list_error) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 3c9cd5d0..a9c301c4 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -20,13 +20,16 @@ Preferences window """ import logging -from functools import partial - from PySide import QtCore, QtGui 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.gui.preferences_account_page import PreferencesAccountPage +from leap.bitmask.gui.preferences_vpn_page import PreferencesVpnPage +from leap.bitmask.gui.preferences_email_page import PreferencesEmailPage + from leap.bitmask.services import get_service_display_name, MX_SERVICE logger = logging.getLogger(__name__) @@ -38,8 +41,7 @@ class PreferencesWindow(QtGui.QDialog): """ preferences_saved = QtCore.Signal() - def __init__(self, parent, username, domain, backend, soledad_started, mx, - leap_signaler): + def __init__(self, parent, username, domain, backend, soledad_started, leap_signaler): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -51,397 +53,94 @@ class PreferencesWindow(QtGui.QDialog): :type backend: Backend :param soledad_started: whether soledad has started or not :type soledad_started: bool - :param mx: whether the current provider provides mx or not. - :type mx: bool + :param leap_signaler: signal server + :type leap_signaler: LeapSignaler """ QtGui.QDialog.__init__(self, parent) - self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") + self._parent = parent self._username = username self._domain = domain self._leap_signaler = leap_signaler self._backend = backend self._soledad_started = soledad_started - self._mx_provided = mx self._settings = LeapSettings() - self._backend_connect() # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) - self.ui.lblPasswordChangeStatus.setVisible(False) - self.ui.lblProvidersServicesStatus.setVisible(False) - - self._selected_services = set() - - # Connections - self.ui.pbChangePassword.clicked.connect(self._change_password) - self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( - self._populate_services) - - if not self._settings.get_configured_providers(): - self.ui.gbEnabledServices.setEnabled(False) - else: - self._add_configured_providers() - if self._username is None: - self._not_logged_in() - else: - self.ui.gbPasswordChange.setEnabled(True) - if self._mx_provided: - self._provides_mx() + self.ui.close_button.clicked.connect(self.close) - self._select_provider_by_name(domain) + self._add_icons() + self._add_pages() - def _not_logged_in(self): + def _add_icons(self): """ - Actions to perform if the user is not logged in. - """ - msg = self.tr( - "In order to change your password you need to be logged in.") - self._set_password_change_status(msg) - self.ui.gbPasswordChange.setEnabled(False) + Adds all the icons for the different configuration categories. + Icons are QListWidgetItems added to the nav_widget on the side + of the preferences window. - def _provides_mx(self): - """ - Actions to perform if the provider provides MX. + A note on sizing of QListWidgetItems + icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 + icon_height = 56 seems to look ok """ - pw_enabled = True - enabled_services = self._settings.get_enabled_services(self._domain) - mx_name = get_service_display_name(MX_SERVICE) + account_button = QtGui.QListWidgetItem(self.ui.nav_widget) + account_button.setIcon(QtGui.QIcon(":/images/black/32/user.png")) + account_button.setText(self.tr("Account")) + account_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + account_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + account_button.setSizeHint(QtCore.QSize(98,56)) - 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 + vpn_button = QtGui.QListWidgetItem(self.ui.nav_widget) + vpn_button.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) + vpn_button.setText(self.tr("VPN")) + vpn_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + vpn_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + vpn_button.setSizeHint(QtCore.QSize(98,56)) - self.ui.gbPasswordChange.setEnabled(pw_enabled) + email_button = QtGui.QListWidgetItem(self.ui.nav_widget) + email_button.setIcon(QtGui.QIcon(":/images/black/32/email.png")) + email_button.setText(self.tr("Email")) + email_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + email_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + email_button.setSizeHint(QtCore.QSize(98,56)) - @QtCore.Slot() - def set_soledad_ready(self): - """ - TRIGGERS: - parent.soledad_ready + self.ui.nav_widget.currentItemChanged.connect(self._change_page) + self.ui.nav_widget.setCurrentRow(0) - It notifies when the soledad object as ready to use. + def _add_pages(self): """ - self.ui.lblPasswordChangeStatus.setVisible(False) - self.ui.gbPasswordChange.setEnabled(True) - - def _set_password_change_status(self, status, error=False, success=False): + Adds the pages for the different configuration categories. """ - Sets the status label for the password change. + self.ui.pages_widget.addWidget(PreferencesAccountPage(self)) + self.ui.pages_widget.addWidget(PreferencesVpnPage(self, self._domain, self._backend, self._leap_signaler)) + self.ui.pages_widget.addWidget(PreferencesEmailPage(self)) - :param status: status message to display, can be HTML - :type status: str - """ - if error: - status = "%s" % (status,) - elif success: - status = "%s" % (status,) - - if not self.ui.gbPasswordChange.isEnabled(): - status = "%s" % (status,) - - self.ui.lblPasswordChangeStatus.setVisible(True) - self.ui.lblPasswordChangeStatus.setText(status) - - def _set_changing_password(self, disable): - """ - Enables or disables the widgets in the password change group box. - - :param disable: True if the widgets should be disabled and - it displays the status label that shows that is - changing the password. - False if they should be enabled. - :type disable: bool - """ - if disable: - self._set_password_change_status(self.tr("Changing password...")) - - self.ui.leCurrentPassword.setEnabled(not disable) - self.ui.leNewPassword.setEnabled(not disable) - self.ui.leNewPassword2.setEnabled(not disable) - self.ui.pbChangePassword.setEnabled(not disable) + # + # Slots + # @QtCore.Slot() - def _change_password(self): + def close(self): """ TRIGGERS: - self.ui.pbChangePassword.clicked + self.ui.close_button.clicked - Changes the user's password if the inputboxes are correctly filled. + Close this dialog """ - username = self._username - current_password = self.ui.leCurrentPassword.text() - new_password = self.ui.leNewPassword.text() - new_password2 = self.ui.leNewPassword2.text() - - ok, msg = password_checks(username, new_password, new_password2) - - if not ok: - self._set_changing_password(False) - self._set_password_change_status(msg, error=True) - self.ui.leNewPassword.setFocus() - return - - self._set_changing_password(True) - self._backend.user_change_password(current_password=current_password, - new_password=new_password) + self._parent.preferences = None + self.hide() @QtCore.Slot() - def _srp_change_password_ok(self): - """ - TRIGGERS: - self._backend.signaler.srp_password_change_ok - - Callback used to display a successfully changed password. - """ - new_password = self.ui.leNewPassword.text() - logger.debug("SRP password changed successfully.") - - if self._mx_provided: - self._backend.soledad_change_password(new_password=new_password) - else: - self._change_password_success() - - @QtCore.Slot(unicode) - def _srp_change_password_problem(self, msg): - """ - TRIGGERS: - self._backend.signaler.srp_password_change_error - self._backend.signaler.srp_password_change_badpw - - Callback used to display an error on changing password. - - :param msg: the message to show to the user. - :type msg: unicode - """ - logger.error("Error changing password") - self._set_password_change_status(msg, error=True) - self._set_changing_password(False) - - @QtCore.Slot() - def _soledad_change_password_ok(self): - """ - TRIGGERS: - Signaler.soledad_password_change_ok - - Soledad password change went OK. - """ - logger.debug("Soledad password changed successfully.") - self._change_password_success() - - def _change_password_success(self): - """ - Callback used to display a successfully changed password. - """ - logger.debug("Soledad password changed successfully.") - - self._set_password_change_status( - self.tr("Password changed successfully."), success=True) - self._clear_password_inputs() - self._set_changing_password(False) - - @QtCore.Slot(unicode) - def _soledad_change_password_problem(self, msg): - """ - TRIGGERS: - Signaler.soledad_password_change_error - - Callback used to display an error on changing password. - - :param msg: the message to show to the user. - :type msg: unicode - """ - logger.error("Error changing soledad password") - self._set_password_change_status(msg, error=True) - self._set_changing_password(False) - - 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 - :param success: is set to True if we should display the - message as green - :type success: bool - """ - 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() - for provider in self._settings.get_configured_providers(): - self.ui.cbProvidersServices.addItem(provider) - - def _select_provider_by_name(self, name): - """ - Given a provider name/domain, selects it in the combobox. - - :param name: name or domain for the provider - :type name: str - """ - provider_index = self.ui.cbProvidersServices.findText(name) - self.ui.cbProvidersServices.setCurrentIndex(provider_index) - - @QtCore.Slot(str, int) - def _service_selection_changed(self, service, state): + def _change_page(self, current, previous): """ TRIGGERS: - service_checkbox.stateChanged + self.ui.nav_widget.currentItemChanged - 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) - - @QtCore.Slot(str) - def _populate_services(self, domain): + Changes what page is displayed. """ - TRIGGERS: - self.ui.cbProvidersServices.currentIndexChanged[unicode] - - Fill the services list with the selected provider's services. - - :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) - - if not domain: - 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) - - self._backend.provider_get_supported_services(domain=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 - 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_label = get_service_display_name(service) - checkbox.setText(service_label) - - 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,)) - - @QtCore.Slot(str) - def _save_enabled_services(self, provider): - """ - TRIGGERS: - self.ui.pbSaveServices.clicked - - Saves the new enabled services 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) - self.preferences_saved.emit() - - def _backend_connect(self): - """ - Helper to connect to backend signals - """ - sig = self._leap_signaler - - sig.prov_get_supported_services.connect(self._load_services) - - sig.srp_password_change_ok.connect(self._srp_change_password_ok) - - pwd_change_error = lambda: self._srp_change_password_problem( - self.tr("There was a problem changing the password.")) - sig.srp_password_change_error.connect(pwd_change_error) - - pwd_change_badpw = lambda: self._srp_change_password_problem( - self.tr("You did not enter a correct current password.")) - sig.srp_password_change_badpw.connect(pwd_change_badpw) - - sig.soledad_password_change_ok.connect( - self._soledad_change_password_ok) - - sig.soledad_password_change_error.connect( - self._soledad_change_password_problem) + if not current: + current = previous + self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) diff --git a/src/leap/bitmask/gui/ui/eippreferences.ui b/src/leap/bitmask/gui/ui/eippreferences.ui deleted file mode 100644 index 1a5fcd24..00000000 --- a/src/leap/bitmask/gui/ui/eippreferences.ui +++ /dev/null @@ -1,102 +0,0 @@ - - - EIPPreferences - - - - 0 - 0 - 435 - 144 - - - - Encrypted Internet Preferences - - - - :/images/mask-icon.png:/images/mask-icon.png - - - - - - true - - - Select gateway for provider - - - false - - - - - - Select &provider: - - - cbProvidersGateway - - - - - - - - <Select provider> - - - - - - - - &Save this provider settings - - - - - - - < Providers Gateway Status > - - - Qt::AlignCenter - - - - - - - Select &gateway: - - - cbGateways - - - - - - - - Automatic - - - - - - - - - - - cbProvidersGateway - cbGateways - pbSaveGateway - - - - - - diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index f7570ee6..2e8aea8c 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -317,7 +317,6 @@ - @@ -338,12 +337,7 @@ true - Account Preferences... - - - - - Internet Preferences... + Preferences... diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index cd4d3a77..5e30ea57 100644 --- a/src/leap/bitmask/gui/ui/preferences.ui +++ b/src/leap/bitmask/gui/ui/preferences.ui @@ -6,8 +6,8 @@ 0 0 - 503 - 401 + 520 + 439 @@ -17,159 +17,97 @@ :/images/mask-icon.png:/images/mask-icon.png - - - - - Qt::Vertical + + + 6 + + + + + + 75 + true + - - - 20 - 40 - + + user@example.org - + - - - - false - - - Password Change + + + + Qt::Horizontal - - - QFormLayout::ExpandingFieldsGrow - - - - - &Current password: - - - leCurrentPassword - - - - - - - QLineEdit::Password - - - - - - - &New password: - - - leNewPassword - - - - - - - QLineEdit::Password - - - - - - - &Re-enter new password: - - - leNewPassword2 - - - - - - - QLineEdit::Password - - - - - - - Change - - - - - - - <Password change status> - - - Qt::AlignCenter - - - - - - - - Enabled services + + + + 12 - - - - - Save this provider settings - - - - - - - Services - - - false - - - - - - - - - - - - - <Select provider> - - - - - - - - Select provider: - - - - - - - < Providers Services Status > - - - Qt::AlignCenter - - - - - + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + + 32 + 32 + + + + QListView::Static + + + 10 + + + QListView::IconMode + + + true + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + diff --git a/src/leap/bitmask/gui/ui/preferences_account_page.ui b/src/leap/bitmask/gui/ui/preferences_account_page.ui new file mode 100644 index 00000000..4e58b2ab --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_account_page.ui @@ -0,0 +1,95 @@ + + + PreferencesAccountPage + + + + 0 + 0 + 462 + 371 + + + + Form + + + + + + + 0 + 0 + + + + Change Password + + + + + + + <change password status> + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 15 + + + + + + + + Services + + + false + + + + + + + + + < Providers Services Status > + + + Qt::AlignCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/leap/bitmask/gui/ui/preferences_email_page.ui b/src/leap/bitmask/gui/ui/preferences_email_page.ui new file mode 100644 index 00000000..41b3c28d --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_email_page.ui @@ -0,0 +1,32 @@ + + + PreferencesEmailPage + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + 250 + 210 + 98 + 27 + + + + PushButton + + + + + + diff --git a/src/leap/bitmask/gui/ui/preferences_vpn_page.ui b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui new file mode 100644 index 00000000..85a0dc60 --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui @@ -0,0 +1,89 @@ + + + PreferencesVpnPage + + + + 0 + 0 + 400 + 362 + + + + Form + + + + + + <flash_label> + + + Qt::AlignCenter + + + + + + + Default VPN Gateway: + + + gateways_list + + + + + + + + New Item + + + + :/images/countries/us.png + + + + + + New Item + + + + :/images/countries/br.png + + + + + + + + + + 0 + 0 + + + + You must reconnect for changes to take effect. + + + false + + + true + + + gateways_list + + + + + + + + + + diff --git a/src/leap/bitmask/services/eip/eipconfig.py b/src/leap/bitmask/services/eip/eipconfig.py index 37c0c8ae..5b51d12e 100644 --- a/src/leap/bitmask/services/eip/eipconfig.py +++ b/src/leap/bitmask/services/eip/eipconfig.py @@ -113,39 +113,38 @@ class VPNGatewaySelector(object): """ Return the existing gateways, sorted by timezone proximity. - :rtype: list of tuples (location, ip) - (str, IPv4Address or IPv6Address object) + :rtype: list of tuples (label, ip, country_code) + (str, IPv4Address or IPv6Address object, str) """ gateways_timezones = [] locations = self._eipconfig.get_locations() gateways = self._eipconfig.get_gateways() for idx, gateway in enumerate(gateways): - gateway_location = gateway.get('location') - gateway_distance = 99 # if hasn't location -> should go last - - if gateway_location is not None: - timezone = locations[gateway['location']]['timezone'] - gateway_name = locations[gateway['location']].get('name', None) - if gateway_name is not None: - gateway_location = gateway_name - - gw_offset = int(timezone) - if gw_offset in self.equivalent_timezones: - gw_offset = self.equivalent_timezones[gw_offset] - - gateway_distance = self._get_timezone_distance(gw_offset) + distance = 99 # if hasn't location -> should go last + location = locations.get(gateway.get('location')) + label = gateway.get('location', 'Unknown') + country = 'XX' + if location is not None: + country = location.get('country_code', 'XX') + label = location.get('name', label) + timezone = location.get('timezone') + if timezone is not None: + offset = int(timezone) + if offset in self.equivalent_timezones: + offset = self.equivalent_timezones[offset] + distance = self._get_timezone_distance(offset) ip = self._eipconfig.get_gateway_ip(idx) - gateways_timezones.append((ip, gateway_distance, gateway_location)) + gateways_timezones.append((ip, distance, label, country)) gateways_timezones = sorted(gateways_timezones, key=lambda gw: gw[1]) - gateways = [] - for ip, distance, location in gateways_timezones: - gateways.append((location, ip)) + result = [] + for ip, distance, label, country in gateways_timezones: + result.append((label, ip, country)) - return gateways + return result def get_gateways(self): """ @@ -153,7 +152,7 @@ class VPNGatewaySelector(object): :rtype: list of IPv4Address or IPv6Address object. """ - gateways = [ip for location, ip in self.get_gateways_list()][:4] + gateways = [gateway[1] for gateway in self.get_gateways_list()][:4] return gateways def get_gateways_country_code(self): -- cgit v1.2.3 From 4e7c4b48b4255ceac06900fa9e65824c52e15ba7 Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 4 Sep 2014 17:09:29 -0700 Subject: single pref win: enabled/disable services via preferences window, account page. --- src/leap/bitmask/gui/account.py | 43 +++++++++ src/leap/bitmask/gui/app.py | 68 ++++++++++++++ src/leap/bitmask/gui/mainwindow.py | 87 +++++++---------- src/leap/bitmask/gui/preferences_account_page.py | 103 ++++++--------------- src/leap/bitmask/gui/preferences_email_page.py | 7 +- src/leap/bitmask/gui/preferences_vpn_page.py | 54 ++++++----- src/leap/bitmask/gui/preferenceswindow.py | 90 ++++++++++-------- .../bitmask/gui/ui/preferences_account_page.ui | 67 ++++++++------ src/leap/bitmask/services/eip/conductor.py | 6 ++ 9 files changed, 304 insertions(+), 221 deletions(-) create mode 100644 src/leap/bitmask/gui/account.py create mode 100644 src/leap/bitmask/gui/app.py diff --git a/src/leap/bitmask/gui/account.py b/src/leap/bitmask/gui/account.py new file mode 100644 index 00000000..b08053a9 --- /dev/null +++ b/src/leap/bitmask/gui/account.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . +""" +A frontend GUI object to hold the current username and domain. +""" + +from leap.bitmask.util import make_address +from leap.bitmask.config.leapsettings import LeapSettings + +class Account(): + + def __init__(self, username, domain): + self._settings = LeapSettings() + self.username = username + self.domain = domain + + if self.username is not None: + self.address = make_address(self.username, self.domain) + else: + self.address = self.domain + + def services(self): + """ + returns a list of service name strings + + TODO: this should depend not just on the domain + """ + return self._settings.get_enabled_services(self.domain) + + diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py new file mode 100644 index 00000000..7fcf69af --- /dev/null +++ b/src/leap/bitmask/gui/app.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . +""" +A single App instances holds the signals that are shared among different +frontend UI components. The App also keeps a reference to the backend object +and the signaler get signals from the backend. +""" +import logging + +from functools import partial +from PySide import QtCore, QtGui + +from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.backend.backend_proxy import BackendProxy +from leap.bitmask.backend.leapsignaler import LeapSignaler + +logger = logging.getLogger(__name__) + +class App(QtGui.QWidget): + + #preferences_saved = QtCore.Signal() + + # the user has changed which services are enabled for a particular account + # args: account (Account), active services (list of str) + service_selection_changed = QtCore.Signal(object, list) + + def __init__(self): + QtGui.QWidget.__init__(self) + + self.settings = LeapSettings() + self.backend = BackendProxy() + self.signaler = LeapSignaler() + self.signaler.start() + + # periodically check if the backend is alive + self._backend_checker = QtCore.QTimer(self) + self._backend_checker.timeout.connect(self._check_backend_status) + self._backend_checker.start(2000) + + + @QtCore.Slot() + def _check_backend_status(self): + """ + TRIGGERS: + self._backend_checker.timeout + + Check that the backend is running. Otherwise show an error to the user. + """ + if not self.backend.online: + logger.critical("Backend is not online.") + QtGui.QMessageBox.critical( + self, self.tr("Application error"), + self.tr("There is a problem contacting the backend, please " + "restart Bitmask.")) + self._backend_checker.stop() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 243fe117..b106364d 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -45,6 +45,8 @@ 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.gui.account import Account +from leap.bitmask.gui.app import App from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init import locks @@ -126,19 +128,10 @@ class MainWindow(QtGui.QMainWindow): self.ui.setupUi(self) self.menuBar().setNativeMenuBar(not IS_LINUX) - self._backend = BackendProxy() - - # periodically check if the backend is alive - self._backend_checker = QtCore.QTimer(self) - self._backend_checker.timeout.connect(self._check_backend_status) - self._backend_checker.start(2000) - - self._leap_signaler = LeapSignaler() - self._leap_signaler.start() - - self._settings = LeapSettings() - # gateway = self._settings.get_selected_gateway(provider) - # self._backend.settings_set_selected_gateway(provider, gateway) + self.app = App() + self._backend = self.app.backend + self._leap_signaler = self.app.signaler + self._settings = self.app.settings # Login Widget self._login_widget = LoginWidget(self._settings, self) @@ -154,6 +147,7 @@ class MainWindow(QtGui.QMainWindow): # Qt Signal Connections ##################################### # TODO separate logic from ui signals. + self.app.service_selection_changed.connect(self._update_eip_enabled_status) self._login_widget.login.connect(self._login) self._login_widget.cancel_login.connect(self._cancel_login) self._login_widget.logout.connect(self._logout) @@ -245,9 +239,6 @@ class MainWindow(QtGui.QMainWindow): self._action_visible = QtGui.QAction(self.tr("Show Main Window"), self) self._action_visible.triggered.connect(self._ensure_visible) - # disable buttons for now, may come back later. - # self.ui.btnPreferences.clicked.connect(self._show_preferences) - self._enabled_services = [] self._ui_mx_visible = True self._ui_eip_visible = True @@ -342,23 +333,6 @@ class MainWindow(QtGui.QMainWindow): logger.error("Bad call to the backend:") logger.error(data) - @QtCore.Slot() - def _check_backend_status(self): - """ - TRIGGERS: - self._backend_checker.timeout - - Check that the backend is running. Otherwise show an error to the user. - """ - online = self._backend.online - if not online: - logger.critical("Backend is not online.") - QtGui.QMessageBox.critical( - self, self.tr("Application error"), - self.tr("There is a problem contacting the backend, please " - "restart Bitmask.")) - self._backend_checker.stop() - def _backend_connect(self, only_tracked=False): """ Connect to backend signals. @@ -598,21 +572,18 @@ class MainWindow(QtGui.QMainWindow): Display the preferences window. """ - user = self._logged_user - domain = self._providers.get_selected_provider() + account = Account(self._logged_user, + self._providers.get_selected_provider()) if self.preferences is not None: self.preferences.close() - self.preferences = PreferencesWindow(self, user, domain, - self._backend, - self._soledad_started, - self._leap_signaler) + self.preferences = PreferencesWindow(self, account, self.app) self.preferences.show() - @QtCore.Slot() - def _update_eip_enabled_status(self): + @QtCore.Slot(object, list) + def _update_eip_enabled_status(self, account=None, services=None): """ TRIGGER: - PreferencesWindow.preferences_saved + App.service_selection_changed Enable or disable the EIP start/stop actions and stop EIP if the user disabled that service. @@ -620,24 +591,35 @@ class MainWindow(QtGui.QMainWindow): :returns: if the eip actions were enabled or disabled :rtype: bool """ - settings = self._settings - default_provider = settings.get_defaultprovider() + if account is not None: + domain = account.domain + else: + # I am not sure why, but asking for the currently selected + # provider here give you the WRONG provider + domain = self.app.settings.get_defaultprovider() - if default_provider is None: + if domain is None: logger.warning("Trying to update eip enabled status but there's no" " default provider. Disabling EIP for the time" " being...") self._backend_cannot_start_eip() return - self._trying_to_start_eip = settings.get_autostart_eip() - self._backend.eip_can_start(domain=default_provider) + if not EIP_SERVICE in self.app.settings.get_enabled_services(domain): + self._eip_conductor.terminate() + def hide(): + self.app.backend.eip_can_start(domain=domain) + QtDelayedCall(100, hide) + # ^^ VERY VERY Hacky, but with the simple state machine, + # there is no way to signal 'disconnect and then disable' + + else: + self._trying_to_start_eip = self.app.settings.get_autostart_eip() + if not self._trying_to_start_eip: + self._backend.eip_setup(provider=domain, skip_network=True) + # check if EIP can start (will trigger widget update) + self.app.backend.eip_can_start(domain=domain) - # If we don't want to start eip, we leave everything - # initialized to quickly start it - if not self._trying_to_start_eip: - self._backend.eip_setup(provider=default_provider, - skip_network=True) def _backend_can_start_eip(self): """ @@ -657,7 +639,6 @@ class MainWindow(QtGui.QMainWindow): enabled_services = [] if default_provider is not None: enabled_services = settings.get_enabled_services(default_provider) - eip_enabled = False if EIP_SERVICE in enabled_services: eip_enabled = True diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index 9cc94482..bb90aab5 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -22,35 +22,29 @@ from functools import partial from PySide import QtCore, QtGui from ui_preferences_account_page import Ui_PreferencesAccountPage +from leap.bitmask.services import get_service_display_name +from leap.bitmask.config.leapsettings import LeapSettings logger = logging.getLogger(__name__) class PreferencesAccountPage(QtGui.QWidget): - """ - """ - - def __init__(self, parent): + def __init__(self, parent, account, app): """ """ QtGui.QWidget.__init__(self, parent) self.ui = Ui_PreferencesAccountPage() self.ui.setupUi(self) - self.show() - self._selected_services = set() - #self._leap_signaler.prov_get_supported_services.connect(self._load_services) + self.account = account + self.app = app - @QtCore.Slot() - def set_soledad_ready(self): - """ - TRIGGERS: - parent.soledad_ready + self._selected_services = set() + self.ui.change_password_label.setVisible(False) + self.ui.provider_services_label.setVisible(False) - It notifies when the soledad object as ready to use. - """ - #self.ui.lblPasswordChangeStatus.setVisible(False) - #self.ui.gbPasswordChange.setEnabled(True) + app.signaler.prov_get_supported_services.connect(self._load_services) + app.backend.provider_get_supported_services(domain=account.domain) @QtCore.Slot(str, int) def _service_selection_changed(self, service, state): @@ -72,94 +66,49 @@ class PreferencesAccountPage(QtGui.QWidget): else: self._selected_services = \ self._selected_services.difference(set([service])) + services = list(self._selected_services) # We hide the maybe-visible status label after a change - self.ui.lblProvidersServicesStatus.setVisible(False) + self.ui.provider_services_label.setVisible(False) - @QtCore.Slot(str) - def _populate_services(self, domain): - """ - TRIGGERS: - self.ui.cbProvidersServices.currentIndexChanged[unicode] - - Fill the services list with the selected provider's services. - - :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) + # write to config + self.app.settings.set_enabled_services(self.account.domain, services) - if not domain: - return + # emit signal alerting change + self.app.service_selection_changed.emit(self.account, services) - # 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) - - self._backend.provider_get_supported_services(domain=domain) @QtCore.Slot(str) def _load_services(self, services): """ TRIGGERS: - self.ui.cbProvidersServices.currentIndexChanged[unicode] + prov_get_supported_services 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 + :param services: list of supported service names + :type services: list of str """ - domain = self.ui.cbProvidersServices.currentText() - services_conf = self._settings.get_enabled_services(domain) + services_conf = self.account.services() - # 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 + layout = self.ui.provider_services_layout for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) - # add one checkbox per service and set the current configured value + # add one checkbox per service and set the current value + # from what is saved in settings. for service in services: try: - checkbox = QtGui.QCheckBox(self) - service_label = get_service_display_name(service) - checkbox.setText(service_label) - - self.ui.vlServices.addWidget(checkbox) + checkbox = QtGui.QCheckBox( + get_service_display_name(service), self) + self.ui.provider_services_layout.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,)) - - @QtCore.Slot(str) - def _save_enabled_services(self, provider): - """ - TRIGGERS: - self.ui.pbSaveServices.clicked - - Saves the new enabled services 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) - self.preferences_saved.emit() diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py index 08ff5463..da902802 100644 --- a/src/leap/bitmask/gui/preferences_email_page.py +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -28,11 +28,14 @@ class PreferencesEmailPage(QtGui.QWidget): """ - def __init__(self, parent): + def __init__(self, parent, account, app): """ """ QtGui.QWidget.__init__(self, parent) self.ui = Ui_PreferencesEmailPage() self.ui.setupUi(self) - self.show() + + self.parent = parent + self.account = account + self.app = app diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py index ba1366e4..a8f074d2 100644 --- a/src/leap/bitmask/gui/preferences_vpn_page.py +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -28,23 +28,22 @@ class PreferencesVpnPage(QtGui.QWidget): Page in the preferences window that shows VPN settings """ - def __init__(self, parent, domain, backend, leap_signaler): + def __init__(self, parent, account, app): """ :param parent: parent object of the EIPPreferencesWindow. :type parent: QWidget - :param domain: the selected by default domain. - :type domain: unicode + :param account: the currently active account + :type account: Account - :param backend: Backend being used - :type backend: Backend + :param app: shared App instance + :type app: App """ QtGui.QWidget.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") - self._settings = LeapSettings() - self._leap_signaler = leap_signaler - self._backend = backend + self.account = account + self.app = app # Load UI self.ui = Ui_PreferencesVpnPage() @@ -53,10 +52,14 @@ class PreferencesVpnPage(QtGui.QWidget): # Connections self.ui.gateways_list.clicked.connect(self._save_selected_gateway) + sig = self.app.signaler + sig.eip_get_gateways_list.connect(self._update_gateways_list) + sig.eip_get_gateways_list_error.connect(self._gateways_list_error) + sig.eip_uninitialized_provider.connect( + self._gateways_list_uninitialized) - self._domain = domain - self._backend_connect() - self._backend.eip_get_gateways_list(domain=domain) + # Trigger update + self.app.backend.eip_get_gateways_list(domain=self.account.domain) def _flash_error(self, message): """ @@ -94,12 +97,13 @@ class PreferencesVpnPage(QtGui.QWidget): item = self.ui.gateways_list.currentItem() if item.text() == self.AUTOMATIC_GATEWAY_LABEL: - gateway = self._settings.GATEWAY_AUTOMATIC + gateway = self.app.settings.GATEWAY_AUTOMATIC else: gateway = item.data(QtCore.Qt.UserRole) - self._settings.set_selected_gateway(self._domain, gateway) - self._backend.settings_set_selected_gateway(provider=self._domain, - gateway=gateway) + self.app.settings.set_selected_gateway(self.account.domain, gateway) + self.app.backend.settings_set_selected_gateway( + provider=self.account.domain, + gateway=gateway) @QtCore.Slot(list) def _update_gateways_list(self, gateways): @@ -116,8 +120,8 @@ class PreferencesVpnPage(QtGui.QWidget): self.ui.gateways_list.clear() self.ui.gateways_list.addItem(self.AUTOMATIC_GATEWAY_LABEL) - selected_gateway = self._settings.get_selected_gateway( - self._domain) + selected_gateway = self.app.settings.get_selected_gateway( + self.account.domain) index = 0 for idx, (gw_name, gw_ip, gw_country) in enumerate(gateways): @@ -144,7 +148,15 @@ class PreferencesVpnPage(QtGui.QWidget): self.tr("Error loading configuration file.")) self.ui.gateways_list.setEnabled(False) - def _backend_connect(self): - sig = self._leap_signaler - sig.eip_get_gateways_list.connect(self._update_gateways_list) - sig.eip_get_gateways_list_error.connect(self._gateways_list_error) + @QtCore.Slot() + def _gateways_list_uninitialized(self): + """ + TRIGGERS: + Signaler.eip_uninitialized_provider + + The requested provider in not initialized yet, so we give the user an + error msg. + """ + self._flash_error( + self.tr("This is an uninitialized provider, please log in first.")) + self.ui.gateways_list.setEnabled(False) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index a9c301c4..35a875fa 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -22,16 +22,13 @@ import logging from PySide import QtCore, QtGui -from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.services import EIP_SERVICE, MX_SERVICE from leap.bitmask.gui.ui_preferences import Ui_Preferences - from leap.bitmask.gui.preferences_account_page import PreferencesAccountPage from leap.bitmask.gui.preferences_vpn_page import PreferencesVpnPage from leap.bitmask.gui.preferences_email_page import PreferencesEmailPage -from leap.bitmask.services import get_service_display_name, MX_SERVICE - logger = logging.getLogger(__name__) @@ -39,9 +36,8 @@ class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ - preferences_saved = QtCore.Signal() - def __init__(self, parent, username, domain, backend, soledad_started, leap_signaler): + def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -51,30 +47,26 @@ class PreferencesWindow(QtGui.QDialog): :type domain: unicode :param backend: Backend being used :type backend: Backend - :param soledad_started: whether soledad has started or not - :type soledad_started: bool :param leap_signaler: signal server :type leap_signaler: LeapSignaler """ QtGui.QDialog.__init__(self, parent) self._parent = parent - self._username = username - self._domain = domain - self._leap_signaler = leap_signaler - self._backend = backend - self._soledad_started = soledad_started - - self._settings = LeapSettings() + self.account = account + self.app = app - # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.close_button.clicked.connect(self.close) + self.ui.account_label.setText(account.address) + + self.app.service_selection_changed.connect(self._update_icons) self._add_icons() self._add_pages() + self._update_icons(self.account, self.account.services()) def _add_icons(self): """ @@ -86,26 +78,31 @@ class PreferencesWindow(QtGui.QDialog): icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 icon_height = 56 seems to look ok """ - account_button = QtGui.QListWidgetItem(self.ui.nav_widget) - account_button.setIcon(QtGui.QIcon(":/images/black/32/user.png")) - account_button.setText(self.tr("Account")) - account_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - account_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - account_button.setSizeHint(QtCore.QSize(98,56)) - - vpn_button = QtGui.QListWidgetItem(self.ui.nav_widget) - vpn_button.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) - vpn_button.setText(self.tr("VPN")) - vpn_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - vpn_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - vpn_button.setSizeHint(QtCore.QSize(98,56)) - - email_button = QtGui.QListWidgetItem(self.ui.nav_widget) - email_button.setIcon(QtGui.QIcon(":/images/black/32/email.png")) - email_button.setText(self.tr("Email")) - email_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - email_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - email_button.setSizeHint(QtCore.QSize(98,56)) + account_item = QtGui.QListWidgetItem(self.ui.nav_widget) + account_item.setIcon(QtGui.QIcon(":/images/black/32/user.png")) + account_item.setText(self.tr("Account")) + account_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + account_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + account_item.setSizeHint(QtCore.QSize(98,56)) + self._account_item = account_item + + vpn_item = QtGui.QListWidgetItem(self.ui.nav_widget) + vpn_item.setHidden(True) + vpn_item.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) + vpn_item.setText(self.tr("VPN")) + vpn_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + vpn_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + vpn_item.setSizeHint(QtCore.QSize(98,56)) + self._vpn_item = vpn_item + + email_item = QtGui.QListWidgetItem(self.ui.nav_widget) + email_item.setHidden(True) + email_item.setIcon(QtGui.QIcon(":/images/black/32/email.png")) + email_item.setText(self.tr("Email")) + email_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + email_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + email_item.setSizeHint(QtCore.QSize(98,56)) + self._email_item = email_item self.ui.nav_widget.currentItemChanged.connect(self._change_page) self.ui.nav_widget.setCurrentRow(0) @@ -114,9 +111,9 @@ class PreferencesWindow(QtGui.QDialog): """ Adds the pages for the different configuration categories. """ - self.ui.pages_widget.addWidget(PreferencesAccountPage(self)) - self.ui.pages_widget.addWidget(PreferencesVpnPage(self, self._domain, self._backend, self._leap_signaler)) - self.ui.pages_widget.addWidget(PreferencesEmailPage(self)) + self.ui.pages_widget.addWidget(PreferencesAccountPage(self, self.account, self.app)) + self.ui.pages_widget.addWidget(PreferencesVpnPage(self, self.account, self.app)) + self.ui.pages_widget.addWidget(PreferencesEmailPage(self, self.account, self.app)) # # Slots @@ -144,3 +141,18 @@ class PreferencesWindow(QtGui.QDialog): if not current: current = previous self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) + + @QtCore.Slot(object, list) + def _update_icons(self, account, services): + """ + TRIGGERS: + self.app.service_selection_changed + + Change which icons are visible. + """ + if account != self.account: + return + + self._vpn_item.setHidden(not EIP_SERVICE in services) + #self._email_item.setHidden(not MX_SERVICE in services) + # ^^ disable email for now, there is nothing there yet. diff --git a/src/leap/bitmask/gui/ui/preferences_account_page.ui b/src/leap/bitmask/gui/ui/preferences_account_page.ui index 4e58b2ab..9b6d885b 100644 --- a/src/leap/bitmask/gui/ui/preferences_account_page.ui +++ b/src/leap/bitmask/gui/ui/preferences_account_page.ui @@ -15,23 +15,28 @@ - - - - 0 - 0 - - - - Change Password + + + Services - - - - - - <change password status> + + false + + + + + + + + <provider_services_label> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + @@ -51,24 +56,28 @@ - + - Services + Password - - false - - - - - - - + + + + + + 0 + 0 + + - < Providers Services Status > + Change Password - - Qt::AlignCenter + + + + + + <change_password_label> diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index 0ee56628..01dd7449 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -124,6 +124,12 @@ class EIPConductor(object): """ self._backend.tear_fw_down() + def terminate(self): + """ + Turn off VPN + """ + self.qtsigs.do_disconnect_signal.emit() + @QtCore.Slot() def _start_eip(self): """ -- cgit v1.2.3 From 6166ffedcae0763f3c00076c79e74847f5c80823 Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 8 Sep 2014 02:01:14 -0700 Subject: single pref win: moved password change UI to a separate window, opened from account page in preferences. --- src/leap/bitmask/gui/account.py | 16 +- src/leap/bitmask/gui/flashable.py | 75 +++++++ src/leap/bitmask/gui/passwordwindow.py | 269 +++++++++++++++++++++++ src/leap/bitmask/gui/preferences_account_page.py | 15 ++ src/leap/bitmask/gui/ui/password_change.ui | 182 +++++++++++++++ src/leap/bitmask/gui/wizard.py | 2 +- src/leap/bitmask/util/credentials.py | 24 +- 7 files changed, 568 insertions(+), 15 deletions(-) create mode 100644 src/leap/bitmask/gui/flashable.py create mode 100644 src/leap/bitmask/gui/passwordwindow.py create mode 100644 src/leap/bitmask/gui/ui/password_change.ui diff --git a/src/leap/bitmask/gui/account.py b/src/leap/bitmask/gui/account.py index b08053a9..ae8127c0 100644 --- a/src/leap/bitmask/gui/account.py +++ b/src/leap/bitmask/gui/account.py @@ -19,6 +19,7 @@ A frontend GUI object to hold the current username and domain. from leap.bitmask.util import make_address from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.services import EIP_SERVICE, MX_SERVICE class Account(): @@ -33,11 +34,16 @@ class Account(): self.address = self.domain def services(self): - """ - returns a list of service name strings + """ + returns a list of service name strings - TODO: this should depend not just on the domain - """ - return self._settings.get_enabled_services(self.domain) + TODO: this should depend not just on the domain + """ + return self._settings.get_enabled_services(self.domain) + def is_email_enabled(self): + MX_SERVICE in self.services() + + def is_eip_enabled(self): + EIP_SERVICE in self.services() diff --git a/src/leap/bitmask/gui/flashable.py b/src/leap/bitmask/gui/flashable.py new file mode 100644 index 00000000..94e3ab60 --- /dev/null +++ b/src/leap/bitmask/gui/flashable.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 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 . + +class Flashable(object): + """ + An abstract super class to give a QWidget handy methods for diplaying + alert messages inline. The widget inheriting from this class must have + label named 'flash_label' available at self.ui.flash_label, or pass + the QLabel object in the constructor. + """ + + def __init__(self, widget=None): + self._setup(widget) + + def _setup(self, widget=None): + if not hasattr(self, 'widget'): + if widget: + self.widget = widget + else: + self.widget = self.ui.flash_label + self.widget.setVisible(False) + + def flash_error(self, message): + """ + Sets string for the flash message. + + :param message: the text to be displayed + :type message: str + """ + self._setup() + message = "%s" % (message,) + self.widget.setVisible(True) + self.widget.setText(message) + + def flash_success(self, message): + """ + Sets string for the flash message. + + :param message: the text to be displayed + :type message: str + """ + self._setup() + message = "%s" % (message,) + self.widget.setVisible(True) + self.widget.setText(message) + + def flash_message(self, message): + """ + Sets string for the flash message. + + :param message: the text to be displayed + :type message: str + """ + self._setup() + message = "%s" % (message,) + self.widget.setVisible(True) + self.widget.setText(message) + + def hide_flash(self): + self._setup() + self.widget.setVisible(False) + diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py new file mode 100644 index 00000000..9946febe --- /dev/null +++ b/src/leap/bitmask/gui/passwordwindow.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- +# passwordwindow.py +# Copyright (C) 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 . + +""" +Change password dialog window +""" + +from PySide import QtCore, QtGui +from leap.bitmask.util.credentials import password_checks + +from leap.bitmask.gui.ui_password_change import Ui_PasswordChange +from leap.bitmask.gui.flashable import Flashable + +import logging +logger = logging.getLogger(__name__) + +class PasswordWindow(QtGui.QDialog, Flashable): + + def __init__(self, parent, account, app): + """ + :param parent: parent object of the PreferencesWindow. + :parent type: QWidget + + :param account: the user set in the login widget + :type account: Account + + :param app: App instance + :type app: App + """ + QtGui.QDialog.__init__(self, parent) + + self.account = account + self.app = app + self._backend_connect() + + self.ui = Ui_PasswordChange() + self.ui.setupUi(self) + + self.hide_flash() + self.ui.ok_button.clicked.connect(self._change_password) + self.ui.cancel_button.clicked.connect(self._close) + self.ui.username_lineedit.setText(account.address) + + self._disabled = False # if set to True, never again enable widgets. + + if account.username is None: + # should not ever happen, but just in case + self._disabled = True + self._enable_password_widgets(False) + self.ui.cancel_button.setEnabled(True) + self.flash_error(self.tr("Please log in to change your password.")) + + if self.is_soledad_needed() and not self._soledad_ready: + self._enable_password_widgets(False) + self.ui.cancel_button.setEnabled(True) + self.flash_message( + self.tr("Please wait for data storage to be ready.")) + + def is_soledad_needed(self): + """ + Returns true if the current account needs to change the soledad + password as well as the SRP password. + """ + return self.account.is_email_enabled() + + # + # MANAGE WIDGETS + # + + def _enable_password_widgets(self, enabled): + """ + Enables or disables the widgets in the password change group box. + + :param enabled: True if the widgets should be enabled. + False if widgets should be disabled and + display the status label that shows that is + changing the password. + :type enabled: bool + """ + if self._disabled: + return + + if enabled: + self.hide_flash() + else: + self.flash_message(self.tr("Changing password...")) + + self.ui.current_password_lineedit.setEnabled(enabled) + self.ui.new_password_lineedit.setEnabled(enabled) + self.ui.new_password_confirmation_lineedit.setEnabled(enabled) + self.ui.ok_button.setEnabled(enabled) + self.ui.cancel_button.setEnabled(enabled) + + def _change_password_success(self): + """ + Callback used to display a successfully changed password. + """ + logger.debug("Password changed successfully.") + self._clear_password_inputs() + self._enable_password_widgets(True) + self.flash_success(self.tr("Password changed successfully.")) + + def _clear_password_inputs(self): + """ + Clear the contents of the inputs. + """ + self.ui.current_password_lineedit.setText("") + self.ui.new_password_lineedit.setText("") + self.ui.new_password_confirmation_lineedit.setText("") + + # + # SLOTS + # + + def _backend_connect(self): + """ + Helper to connect to backend signals + """ + sig = self.app.signaler + + sig.srp_password_change_ok.connect(self._srp_change_password_ok) + + pwd_change_error = lambda: self._srp_change_password_problem( + self.tr("There was a problem changing the password."), + None) + sig.srp_password_change_error.connect(pwd_change_error) + + pwd_change_badpw = lambda: self._srp_change_password_problem( + self.tr("You did not enter a correct current password."), + 'current_password') + sig.srp_password_change_badpw.connect(pwd_change_badpw) + + sig.soledad_password_change_ok.connect( + self._soledad_change_password_ok) + + sig.soledad_password_change_error.connect( + self._soledad_change_password_problem) + + self._soledad_ready = False + sig.soledad_bootstrap_finished.connect(self._on_soledad_ready) + + + @QtCore.Slot() + def _change_password(self): + """ + TRIGGERS: + self.ui.buttonBox.accepted + + Changes the user's password if the inputboxes are correctly filled. + """ + current_password = self.ui.current_password_lineedit.text() + new_password = self.ui.new_password_lineedit.text() + new_password2 = self.ui.new_password_confirmation_lineedit.text() + + self._enable_password_widgets(True) + + if len(current_password) == 0: + self.flash_error(self.tr("Password is empty.")) + self.ui.current_password_lineedit.setFocus() + return + + ok, msg, field = password_checks(self.account.username, new_password, + new_password2) + if not ok: + self.flash_error(msg) + if field == 'new_password': + self.ui.new_password_lineedit.setFocus() + elif field == 'new_password_confirmation': + self.ui.new_password_confirmation_lineedit.setFocus() + return + + self._enable_password_widgets(False) + self.app.backend.user_change_password( + current_password=current_password, + new_password=new_password) + + @QtCore.Slot() + def _close(self): + """ + TRIGGERS: + self.ui.buttonBox.rejected + + Close this dialog + """ + self.hide() + + @QtCore.Slot() + def _srp_change_password_ok(self): + """ + TRIGGERS: + self._backend.signaler.srp_password_change_ok + + Callback used to display a successfully changed password. + """ + new_password = self.ui.new_password_lineedit.text() + logger.debug("SRP password changed successfully.") + + if self.is_soledad_needed(): + self._backend.soledad_change_password(new_password=new_password) + else: + self._change_password_success() + + @QtCore.Slot(unicode) + def _srp_change_password_problem(self, msg, field): + """ + TRIGGERS: + self._backend.signaler.srp_password_change_error + self._backend.signaler.srp_password_change_badpw + + Callback used to display an error on changing password. + + :param msg: the message to show to the user. + :type msg: unicode + """ + logger.error("Error changing password: %s" % (msg,)) + self._enable_password_widgets(True) + self.flash_error(msg) + if field == 'current_password': + self.ui.current_password_lineedit.setFocus() + + @QtCore.Slot() + def _soledad_change_password_ok(self): + """ + TRIGGERS: + Signaler.soledad_password_change_ok + + Soledad password change went OK. + """ + logger.debug("Soledad password changed successfully.") + self._change_password_success() + + @QtCore.Slot(unicode) + def _soledad_change_password_problem(self, msg): + """ + TRIGGERS: + Signaler.soledad_password_change_error + + Callback used to display an error on changing password. + + :param msg: the message to show to the user. + :type msg: unicode + """ + logger.error("Error changing soledad password: %s" % (msg,)) + self._enable_password_widgets(True) + self.flash_error(msg) + + + @QtCore.Slot() + def _on_soledad_ready(self): + """ + TRIGGERS: + Signaler.soledad_bootstrap_finished + """ + self._enable_password_widgets(True) + self._soledad_ready = True diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index bb90aab5..895d84b5 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -22,6 +22,7 @@ from functools import partial from PySide import QtCore, QtGui from ui_preferences_account_page import Ui_PreferencesAccountPage +from passwordwindow import PasswordWindow from leap.bitmask.services import get_service_display_name from leap.bitmask.config.leapsettings import LeapSettings @@ -43,9 +44,17 @@ class PreferencesAccountPage(QtGui.QWidget): self.ui.change_password_label.setVisible(False) self.ui.provider_services_label.setVisible(False) + self.ui.change_password_button.clicked.connect( + self._show_change_password) app.signaler.prov_get_supported_services.connect(self._load_services) app.backend.provider_get_supported_services(domain=account.domain) + if account.username is None: + self.ui.change_password_label.setText( + self.tr('You must be logged in to change your password.')) + self.ui.change_password_label.setVisible(True) + self.ui.change_password_button.setEnabled(False) + @QtCore.Slot(str, int) def _service_selection_changed(self, service, state): """ @@ -112,3 +121,9 @@ class PreferencesAccountPage(QtGui.QWidget): except ValueError: logger.error("Something went wrong while trying to " "load service %s" % (service,)) + + @QtCore.Slot() + def _show_change_password(self): + change_password_window = PasswordWindow(self, self.account, self.app) + change_password_window.show() + diff --git a/src/leap/bitmask/gui/ui/password_change.ui b/src/leap/bitmask/gui/ui/password_change.ui new file mode 100644 index 00000000..b7ceac38 --- /dev/null +++ b/src/leap/bitmask/gui/ui/password_change.ui @@ -0,0 +1,182 @@ + + + PasswordChange + + + + 0 + 0 + 459 + 231 + + + + + 0 + 0 + + + + Change Password + + + + + + + + Username: + + + + + + + New password: + + + new_password_lineedit + + + + + + + QLineEdit::Password + + + + + + + Re-enter new password: + + + new_password_confirmation_lineedit + + + + + + + Current password: + + + current_password_lineedit + + + + + + + QLineEdit::Password + + + + + + + QLineEdit::Password + + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + + + false + + + + + + + + + + + <flash_label> + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + false + + + + + + + OK + + + false + + + true + + + + + + + + + username_lineedit + current_password_lineedit + new_password_lineedit + new_password_confirmation_lineedit + + + + diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 8182228d..4d55a39e 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -317,7 +317,7 @@ class Wizard(QtGui.QWizard): user_ok, msg = username_checks(username) if user_ok: - pass_ok, msg = password_checks(username, password, password2) + pass_ok, msg, field = password_checks(username, password, password2) if user_ok and pass_ok: self._set_register_status(self.tr("Starting registration...")) diff --git a/src/leap/bitmask/util/credentials.py b/src/leap/bitmask/util/credentials.py index 757ce10c..dfc78a09 100644 --- a/src/leap/bitmask/util/credentials.py +++ b/src/leap/bitmask/util/credentials.py @@ -38,7 +38,7 @@ def username_checks(username): valid = USERNAME_VALIDATOR.validate(username, 0) valid_username = valid[0] == QtGui.QValidator.State.Acceptable if message is None and not valid_username: - message = _tr("Invalid username") + message = _tr("That username is not allowed. Try another.") return message is None, message @@ -54,28 +54,34 @@ def password_checks(username, password, password2): :param password2: second password from the registration form :type password: str - :returns: True and empty message if all the checks pass, - False and an error message otherwise - :rtype: tuple(bool, str) + :returns: (True, None, None) if all the checks pass, + (False, message, field name) otherwise + :rtype: tuple(bool, str, str) """ # translation helper _tr = QtCore.QObject().tr message = None + field = None if message is None and password != password2: message = _tr("Passwords don't match") + field = 'new_password_confirmation' if message is None and not password: - message = _tr("You can't use an empty password") + message = _tr("Password is empty") + field = 'new_password' if message is None and len(password) < 8: - message = _tr("Password too short") + message = _tr("Password is too short") + field = 'new_password' if message is None and password in WEAK_PASSWORDS: - message = _tr("Password too easy") + message = _tr("Password is too easy") + field = 'new_password' if message is None and username == password: - message = _tr("Password equal to username") + message = _tr("Password can't be the same as username") + field = 'new_password' - return message is None, message + return message is None, message, field -- cgit v1.2.3 From c29b1dd9345e01e761b9891728ecd0b8d964a02d Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 16 Sep 2014 16:40:52 -0700 Subject: single pref win: gets the autopep8 beauty scrub. --- src/leap/bitmask/gui/account.py | 6 ++--- src/leap/bitmask/gui/app.py | 4 +-- src/leap/bitmask/gui/flashable.py | 3 ++- src/leap/bitmask/gui/passwordwindow.py | 7 +++-- src/leap/bitmask/gui/preferences_account_page.py | 3 +-- src/leap/bitmask/gui/preferences_email_page.py | 3 ++- src/leap/bitmask/gui/preferences_vpn_page.py | 1 + src/leap/bitmask/gui/preferenceswindow.py | 33 +++++++++++++++--------- src/leap/bitmask/gui/wizard.py | 4 ++- 9 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/leap/bitmask/gui/account.py b/src/leap/bitmask/gui/account.py index ae8127c0..c941c3fa 100644 --- a/src/leap/bitmask/gui/account.py +++ b/src/leap/bitmask/gui/account.py @@ -21,6 +21,7 @@ from leap.bitmask.util import make_address from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.services import EIP_SERVICE, MX_SERVICE + class Account(): def __init__(self, username, domain): @@ -29,9 +30,9 @@ class Account(): self.domain = domain if self.username is not None: - self.address = make_address(self.username, self.domain) + self.address = make_address(self.username, self.domain) else: - self.address = self.domain + self.address = self.domain def services(self): """ @@ -46,4 +47,3 @@ class Account(): def is_eip_enabled(self): EIP_SERVICE in self.services() - diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py index 7fcf69af..eb1a58d5 100644 --- a/src/leap/bitmask/gui/app.py +++ b/src/leap/bitmask/gui/app.py @@ -29,9 +29,8 @@ from leap.bitmask.backend.leapsignaler import LeapSignaler logger = logging.getLogger(__name__) -class App(QtGui.QWidget): - #preferences_saved = QtCore.Signal() +class App(QtGui.QWidget): # the user has changed which services are enabled for a particular account # args: account (Account), active services (list of str) @@ -50,7 +49,6 @@ class App(QtGui.QWidget): self._backend_checker.timeout.connect(self._check_backend_status) self._backend_checker.start(2000) - @QtCore.Slot() def _check_backend_status(self): """ diff --git a/src/leap/bitmask/gui/flashable.py b/src/leap/bitmask/gui/flashable.py index 94e3ab60..a26d1ec6 100644 --- a/src/leap/bitmask/gui/flashable.py +++ b/src/leap/bitmask/gui/flashable.py @@ -14,7 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . + class Flashable(object): + """ An abstract super class to give a QWidget handy methods for diplaying alert messages inline. The widget inheriting from this class must have @@ -72,4 +74,3 @@ class Flashable(object): def hide_flash(self): self._setup() self.widget.setVisible(False) - diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py index 9946febe..5354ab86 100644 --- a/src/leap/bitmask/gui/passwordwindow.py +++ b/src/leap/bitmask/gui/passwordwindow.py @@ -28,6 +28,7 @@ from leap.bitmask.gui.flashable import Flashable import logging logger = logging.getLogger(__name__) + class PasswordWindow(QtGui.QDialog, Flashable): def __init__(self, parent, account, app): @@ -55,7 +56,7 @@ class PasswordWindow(QtGui.QDialog, Flashable): self.ui.cancel_button.clicked.connect(self._close) self.ui.username_lineedit.setText(account.address) - self._disabled = False # if set to True, never again enable widgets. + self._disabled = False # if set to True, never again enable widgets. if account.username is None: # should not ever happen, but just in case @@ -153,7 +154,6 @@ class PasswordWindow(QtGui.QDialog, Flashable): self._soledad_ready = False sig.soledad_bootstrap_finished.connect(self._on_soledad_ready) - @QtCore.Slot() def _change_password(self): """ @@ -174,7 +174,7 @@ class PasswordWindow(QtGui.QDialog, Flashable): return ok, msg, field = password_checks(self.account.username, new_password, - new_password2) + new_password2) if not ok: self.flash_error(msg) if field == 'new_password': @@ -258,7 +258,6 @@ class PasswordWindow(QtGui.QDialog, Flashable): self._enable_password_widgets(True) self.flash_error(msg) - @QtCore.Slot() def _on_soledad_ready(self): """ diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index 895d84b5..00dbe626 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -28,6 +28,7 @@ from leap.bitmask.config.leapsettings import LeapSettings logger = logging.getLogger(__name__) + class PreferencesAccountPage(QtGui.QWidget): def __init__(self, parent, account, app): @@ -86,7 +87,6 @@ class PreferencesAccountPage(QtGui.QWidget): # emit signal alerting change self.app.service_selection_changed.emit(self.account, services) - @QtCore.Slot(str) def _load_services(self, services): """ @@ -126,4 +126,3 @@ class PreferencesAccountPage(QtGui.QWidget): def _show_change_password(self): change_password_window = PasswordWindow(self, self.account, self.app) change_password_window.show() - diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py index da902802..0535762a 100644 --- a/src/leap/bitmask/gui/preferences_email_page.py +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -23,7 +23,9 @@ from ui_preferences_email_page import Ui_PreferencesEmailPage logger = logging.getLogger(__name__) + class PreferencesEmailPage(QtGui.QWidget): + """ """ @@ -38,4 +40,3 @@ class PreferencesEmailPage(QtGui.QWidget): self.parent = parent self.account = account self.app = app - diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py index a8f074d2..e3417f89 100644 --- a/src/leap/bitmask/gui/preferences_vpn_page.py +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -24,6 +24,7 @@ from leap.bitmask.config.leapsettings import LeapSettings class PreferencesVpnPage(QtGui.QWidget): + """ Page in the preferences window that shows VPN settings """ diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 35a875fa..ccddb764 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -33,6 +33,7 @@ logger = logging.getLogger(__name__) class PreferencesWindow(QtGui.QDialog): + """ Window that displays the preferences. """ @@ -81,27 +82,32 @@ class PreferencesWindow(QtGui.QDialog): account_item = QtGui.QListWidgetItem(self.ui.nav_widget) account_item.setIcon(QtGui.QIcon(":/images/black/32/user.png")) account_item.setText(self.tr("Account")) - account_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - account_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - account_item.setSizeHint(QtCore.QSize(98,56)) + account_item.setTextAlignment( + QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + account_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + account_item.setSizeHint(QtCore.QSize(98, 56)) self._account_item = account_item vpn_item = QtGui.QListWidgetItem(self.ui.nav_widget) vpn_item.setHidden(True) vpn_item.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) vpn_item.setText(self.tr("VPN")) - vpn_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + vpn_item.setTextAlignment( + QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) vpn_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - vpn_item.setSizeHint(QtCore.QSize(98,56)) + vpn_item.setSizeHint(QtCore.QSize(98, 56)) self._vpn_item = vpn_item email_item = QtGui.QListWidgetItem(self.ui.nav_widget) email_item.setHidden(True) email_item.setIcon(QtGui.QIcon(":/images/black/32/email.png")) email_item.setText(self.tr("Email")) - email_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - email_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - email_item.setSizeHint(QtCore.QSize(98,56)) + email_item.setTextAlignment( + QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + email_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + email_item.setSizeHint(QtCore.QSize(98, 56)) self._email_item = email_item self.ui.nav_widget.currentItemChanged.connect(self._change_page) @@ -111,9 +117,12 @@ class PreferencesWindow(QtGui.QDialog): """ Adds the pages for the different configuration categories. """ - self.ui.pages_widget.addWidget(PreferencesAccountPage(self, self.account, self.app)) - self.ui.pages_widget.addWidget(PreferencesVpnPage(self, self.account, self.app)) - self.ui.pages_widget.addWidget(PreferencesEmailPage(self, self.account, self.app)) + self.ui.pages_widget.addWidget( + PreferencesAccountPage(self, self.account, self.app)) + self.ui.pages_widget.addWidget( + PreferencesVpnPage(self, self.account, self.app)) + self.ui.pages_widget.addWidget( + PreferencesEmailPage(self, self.account, self.app)) # # Slots @@ -154,5 +163,5 @@ class PreferencesWindow(QtGui.QDialog): return self._vpn_item.setHidden(not EIP_SERVICE in services) - #self._email_item.setHidden(not MX_SERVICE in services) + # self._email_item.setHidden(not MX_SERVICE in services) # ^^ disable email for now, there is nothing there yet. diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 4d55a39e..ff9cae55 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -42,6 +42,7 @@ logger = logging.getLogger(__name__) class Wizard(QtGui.QWizard): + """ First run wizard to register a user and setup a provider """ @@ -317,7 +318,8 @@ class Wizard(QtGui.QWizard): user_ok, msg = username_checks(username) if user_ok: - pass_ok, msg, field = password_checks(username, password, password2) + pass_ok, msg, field = password_checks( + username, password, password2) if user_ok and pass_ok: self._set_register_status(self.tr("Starting registration...")) -- cgit v1.2.3 From 1d331478a431047bf59fc6249a93e127450bff24 Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 16 Sep 2014 17:07:12 -0700 Subject: single pref win: clean up vpn pref error displaying & don't show dummy gateways in case of error. --- src/leap/bitmask/gui/preferences_vpn_page.py | 31 ++++--------------------- src/leap/bitmask/gui/ui/preferences_vpn_page.ui | 20 ---------------- 2 files changed, 5 insertions(+), 46 deletions(-) diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py index e3417f89..f3fa1ecc 100644 --- a/src/leap/bitmask/gui/preferences_vpn_page.py +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -21,9 +21,9 @@ from PySide import QtCore, QtGui from ui_preferences_vpn_page import Ui_PreferencesVpnPage from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.gui.flashable import Flashable - -class PreferencesVpnPage(QtGui.QWidget): +class PreferencesVpnPage(QtGui.QWidget, Flashable): """ Page in the preferences window that shows VPN settings @@ -50,6 +50,7 @@ class PreferencesVpnPage(QtGui.QWidget): self.ui = Ui_PreferencesVpnPage() self.ui.setupUi(self) self.ui.flash_label.setVisible(False) + self.hide_flash() # Connections self.ui.gateways_list.clicked.connect(self._save_selected_gateway) @@ -62,28 +63,6 @@ class PreferencesVpnPage(QtGui.QWidget): # Trigger update self.app.backend.eip_get_gateways_list(domain=self.account.domain) - def _flash_error(self, message): - """ - Sets string for the flash message. - - :param message: the text to be displayed - :type message: str - """ - message = "%s" % (message,) - self.ui.flash_label.setVisible(True) - self.ui.flash_label.setText(message) - - # def _flash_success(self, message): - # """ - # Sets string for the flash message. - # - # :param message: the text to be displayed - # :type message: str - # """ - # message = "%s" % (message,) - # self.ui.flash_label.setVisible(True) - # self.ui.flash_label.setText(message) - @QtCore.Slot(str) def _save_selected_gateway(self, index): """ @@ -145,7 +124,7 @@ class PreferencesVpnPage(QtGui.QWidget): An error has occurred retrieving the gateway list so we inform the user. """ - self._flash_error( + self.flash_error( self.tr("Error loading configuration file.")) self.ui.gateways_list.setEnabled(False) @@ -158,6 +137,6 @@ class PreferencesVpnPage(QtGui.QWidget): The requested provider in not initialized yet, so we give the user an error msg. """ - self._flash_error( + self.flash_error( self.tr("This is an uninitialized provider, please log in first.")) self.ui.gateways_list.setEnabled(False) diff --git a/src/leap/bitmask/gui/ui/preferences_vpn_page.ui b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui index 85a0dc60..1bf3a060 100644 --- a/src/leap/bitmask/gui/ui/preferences_vpn_page.ui +++ b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui @@ -36,26 +36,6 @@ - - - New Item - - - - :/images/countries/us.png - - - - - - New Item - - - - :/images/countries/br.png - - - -- cgit v1.2.3 From 5f56629884da77c3f1427ef5ceb8a830654eb424 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 17 Sep 2014 16:15:56 -0700 Subject: single pref win: move preference window tracking to PreferencesWindow --- src/leap/bitmask/gui/mainwindow.py | 9 ++------- src/leap/bitmask/gui/preferenceswindow.py | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index b106364d..cc4ede09 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -98,9 +98,6 @@ class MainWindow(QtGui.QMainWindow): # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 3000 # in milliseconds - # Preferences window - preferences = None - def __init__(self, start_hidden=False, backend_pid=None): """ Constructor for the client main window @@ -574,10 +571,8 @@ class MainWindow(QtGui.QMainWindow): """ account = Account(self._logged_user, self._providers.get_selected_provider()) - if self.preferences is not None: - self.preferences.close() - self.preferences = PreferencesWindow(self, account, self.app) - self.preferences.show() + pref_win = PreferencesWindow(self, account, self.app) + pref_win.show() @QtCore.Slot(object, list) def _update_eip_enabled_status(self, account=None, services=None): diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index ccddb764..32651d5c 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -38,22 +38,21 @@ class PreferencesWindow(QtGui.QDialog): Window that displays the preferences. """ + _current_window = None # currently visible preferences window + def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget - :param username: the user set in the login widget - :type username: unicode - :param domain: the selected domain in the login widget - :type domain: unicode - :param backend: Backend being used - :type backend: Backend - :param leap_signaler: signal server - :type leap_signaler: LeapSignaler + + :param account: the user or provider + :type account: Account + + :param app: the current App object + :type app: App """ QtGui.QDialog.__init__(self, parent) - self._parent = parent self.account = account self.app = app @@ -69,6 +68,11 @@ class PreferencesWindow(QtGui.QDialog): self._add_pages() self._update_icons(self.account, self.account.services()) + # only allow a single preferrences window at a time. + if PreferencesWindow._current_window is not None: + PreferencesWindow._current_window.close() + PreferencesWindow._current_window = self + def _add_icons(self): """ Adds all the icons for the different configuration categories. @@ -136,7 +140,7 @@ class PreferencesWindow(QtGui.QDialog): Close this dialog """ - self._parent.preferences = None + PreferencesWindow._current_window = None self.hide() @QtCore.Slot() -- cgit v1.2.3 From d8105d53e3aa66448094df3f34eda54c3dcab865 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 17 Sep 2014 16:42:51 -0700 Subject: single pref win: minor linting & add changes file --- changes/feature-combined-preferences-window | 1 + src/leap/bitmask/gui/preferences_account_page.py | 19 +++++++++++++++---- src/leap/bitmask/gui/preferences_email_page.py | 9 +-------- src/leap/bitmask/gui/preferences_vpn_page.py | 3 ++- src/leap/bitmask/gui/preferenceswindow.py | 6 ++++++ 5 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 changes/feature-combined-preferences-window diff --git a/changes/feature-combined-preferences-window b/changes/feature-combined-preferences-window new file mode 100644 index 00000000..146ac923 --- /dev/null +++ b/changes/feature-combined-preferences-window @@ -0,0 +1 @@ +- single combined preferences window (closes #4704, #4119, #5885) \ No newline at end of file diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index 00dbe626..ec6a7716 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -21,10 +21,9 @@ import logging from functools import partial from PySide import QtCore, QtGui -from ui_preferences_account_page import Ui_PreferencesAccountPage -from passwordwindow import PasswordWindow +from leap.bitmask.gui.ui_preferences_account_page import Ui_PreferencesAccountPage +from leap.bitmask.gui.passwordwindow import PasswordWindow from leap.bitmask.services import get_service_display_name -from leap.bitmask.config.leapsettings import LeapSettings logger = logging.getLogger(__name__) @@ -33,6 +32,14 @@ class PreferencesAccountPage(QtGui.QWidget): def __init__(self, parent, account, app): """ + :param parent: parent object of the PreferencesWindow. + :parent type: QWidget + + :param account: user account (user + provider or just provider) + :type account: Account + + :param app: the current App object + :type app: App """ QtGui.QWidget.__init__(self, parent) self.ui = Ui_PreferencesAccountPage() @@ -103,7 +110,11 @@ class PreferencesAccountPage(QtGui.QWidget): self._selected_services = set() - # remove existing checkboxes + # Remove existing checkboxes + # (the new widget is deleted when its parent is deleted. + # We need to loop backwards because removing things from the + # beginning shifts items and changes the order of items in the layout. + # Using `QObject.deleteLater` doesn't seem to work.) layout = self.ui.provider_services_layout for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py index 0535762a..80e8d93e 100644 --- a/src/leap/bitmask/gui/preferences_email_page.py +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -19,24 +19,17 @@ Widget for "email" preferences import logging from PySide import QtCore, QtGui -from ui_preferences_email_page import Ui_PreferencesEmailPage +from leap.bitmask.gui.ui_preferences_email_page import Ui_PreferencesEmailPage logger = logging.getLogger(__name__) class PreferencesEmailPage(QtGui.QWidget): - """ - - """ - def __init__(self, parent, account, app): - """ - """ QtGui.QWidget.__init__(self, parent) self.ui = Ui_PreferencesEmailPage() self.ui.setupUi(self) - self.parent = parent self.account = account self.app = app diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py index f3fa1ecc..901116b4 100644 --- a/src/leap/bitmask/gui/preferences_vpn_page.py +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -18,11 +18,12 @@ Widget for "vpn" preferences """ from PySide import QtCore, QtGui -from ui_preferences_vpn_page import Ui_PreferencesVpnPage +from leap.bitmask.gui.ui_preferences_vpn_page import Ui_PreferencesVpnPage from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.flashable import Flashable + class PreferencesVpnPage(QtGui.QWidget, Flashable): """ diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 32651d5c..f9b7ddf6 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -150,6 +150,12 @@ class PreferencesWindow(QtGui.QDialog): self.ui.nav_widget.currentItemChanged Changes what page is displayed. + + :param current: the currently selected item (might be None?) + :type current: PySide.QtGui.QListWidgetItem + + :param previous: the previously selected item (might be None) + :type previous: PySide.QtGui.QListWidgetItem """ if not current: current = previous -- cgit v1.2.3 From 92fc4c1d9d60a213a4be21db459efc3bfc3e205f Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 18 Sep 2014 15:17:46 -0700 Subject: single pref win: added shortcut to preferences --- src/leap/bitmask/gui/ui/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 2e8aea8c..b1d68c4a 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -337,7 +337,7 @@ true - Preferences... + Pr&eferences... -- cgit v1.2.3 From 0ad8c8ea3f8d5130f44aa90b55da59622d0048c7 Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 18 Sep 2014 15:18:46 -0700 Subject: single pref win: ensure proper deletion of preference window pages. --- src/leap/bitmask/gui/preferenceswindow.py | 41 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index f9b7ddf6..e18be976 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -38,7 +38,7 @@ class PreferencesWindow(QtGui.QDialog): Window that displays the preferences. """ - _current_window = None # currently visible preferences window + _current_window = None # currently visible preferences window def __init__(self, parent, account, app): """ @@ -59,7 +59,7 @@ class PreferencesWindow(QtGui.QDialog): self.ui = Ui_Preferences() self.ui.setupUi(self) - self.ui.close_button.clicked.connect(self.close) + self.ui.close_button.clicked.connect(self.close_window) self.ui.account_label.setText(account.address) self.app.service_selection_changed.connect(self._update_icons) @@ -68,9 +68,9 @@ class PreferencesWindow(QtGui.QDialog): self._add_pages() self._update_icons(self.account, self.account.services()) - # only allow a single preferrences window at a time. + # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: - PreferencesWindow._current_window.close() + PreferencesWindow._current_window.close_window() PreferencesWindow._current_window = self def _add_icons(self): @@ -121,27 +121,42 @@ class PreferencesWindow(QtGui.QDialog): """ Adds the pages for the different configuration categories. """ - self.ui.pages_widget.addWidget( - PreferencesAccountPage(self, self.account, self.app)) - self.ui.pages_widget.addWidget( - PreferencesVpnPage(self, self.account, self.app)) - self.ui.pages_widget.addWidget( - PreferencesEmailPage(self, self.account, self.app)) + self._account_page = PreferencesAccountPage(self, self.account, self.app) + self._vpn_page = PreferencesVpnPage(self, self.account, self.app) + self._email_page = PreferencesEmailPage(self, self.account, self.app) + + self.ui.pages_widget.addWidget(self._account_page) + self.ui.pages_widget.addWidget(self._vpn_page) + self.ui.pages_widget.addWidget(self._email_page) + + def closeEvent(self, e): + """ + Override closeEvent to capture when user closes the window. + """ + self.close_window() # # Slots # @QtCore.Slot() - def close(self): + def close_window(self): """ TRIGGERS: self.ui.close_button.clicked - Close this dialog + Close this dialog and destroy it. """ PreferencesWindow._current_window = None - self.hide() + self.close() + + # deleteLater does not seem to cascade to items in stackLayout + # (even with QtCore.Qt.WA_DeleteOnClose attribute). + # so, here we call deleteLater() explicitly: + self._account_page.deleteLater() + self._vpn_page.deleteLater() + self._email_page.deleteLater() + self.deleteLater() @QtCore.Slot() def _change_page(self, current, previous): -- cgit v1.2.3 From d47adca6cb7494e55c4a9fbc88896c62c06affa5 Mon Sep 17 00:00:00 2001 From: elijah Date: Fri, 19 Sep 2014 14:22:42 -0700 Subject: single pref win: fix problems with cleaning up closed windows (lambdas were keeping the python object from getting garbage collected, and this keeps the old signal connections active) --- src/leap/bitmask/gui/passwordwindow.py | 61 +++++++++++++++++-------------- src/leap/bitmask/gui/preferenceswindow.py | 14 ++----- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py index 5354ab86..f7ef079e 100644 --- a/src/leap/bitmask/gui/passwordwindow.py +++ b/src/leap/bitmask/gui/passwordwindow.py @@ -31,6 +31,8 @@ logger = logging.getLogger(__name__) class PasswordWindow(QtGui.QDialog, Flashable): + _current_window = None # currently visible password window + def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. @@ -53,9 +55,13 @@ class PasswordWindow(QtGui.QDialog, Flashable): self.hide_flash() self.ui.ok_button.clicked.connect(self._change_password) - self.ui.cancel_button.clicked.connect(self._close) + self.ui.cancel_button.clicked.connect(self.close) self.ui.username_lineedit.setText(account.address) + if PasswordWindow._current_window is not None: + PasswordWindow._current_window.close() + PasswordWindow._current_window = self + self._disabled = False # if set to True, never again enable widgets. if account.username is None: @@ -132,22 +138,11 @@ class PasswordWindow(QtGui.QDialog, Flashable): Helper to connect to backend signals """ sig = self.app.signaler - sig.srp_password_change_ok.connect(self._srp_change_password_ok) - - pwd_change_error = lambda: self._srp_change_password_problem( - self.tr("There was a problem changing the password."), - None) - sig.srp_password_change_error.connect(pwd_change_error) - - pwd_change_badpw = lambda: self._srp_change_password_problem( - self.tr("You did not enter a correct current password."), - 'current_password') - sig.srp_password_change_badpw.connect(pwd_change_badpw) - + sig.srp_password_change_error.connect(self._srp_password_change_error) + sig.srp_password_change_badpw.connect(self._srp_password_change_badpw) sig.soledad_password_change_ok.connect( self._soledad_change_password_ok) - sig.soledad_password_change_error.connect( self._soledad_change_password_problem) @@ -188,15 +183,16 @@ class PasswordWindow(QtGui.QDialog, Flashable): current_password=current_password, new_password=new_password) - @QtCore.Slot() - def _close(self): + def closeEvent(self, event=None): """ TRIGGERS: - self.ui.buttonBox.rejected + cancel_button (indirectly via self.close()) + or when window is closed - Close this dialog + Close this dialog & delete ourselves to clean up signals. """ - self.hide() + PasswordWindow._current_window = None + self.deleteLater() @QtCore.Slot() def _srp_change_password_ok(self): @@ -214,23 +210,32 @@ class PasswordWindow(QtGui.QDialog, Flashable): else: self._change_password_success() - @QtCore.Slot(unicode) - def _srp_change_password_problem(self, msg, field): + @QtCore.Slot() + def _srp_password_change_error(self): """ TRIGGERS: self._backend.signaler.srp_password_change_error - self._backend.signaler.srp_password_change_badpw - Callback used to display an error on changing password. + Unknown problem changing password + """ + msg = self.tr("There was a problem changing the password.") + logger.error(msg) + self._enable_password_widgets(True) + self.flash_error(msg) - :param msg: the message to show to the user. - :type msg: unicode + @QtCore.Slot() + def _srp_password_change_badpw(self): """ - logger.error("Error changing password: %s" % (msg,)) + TRIGGERS: + self._backend.signaler.srp_password_change_badpw + + The password the user entered was wrong. + """ + msg = self.tr("You did not enter a correct current password.") + logger.error(msg) self._enable_password_widgets(True) self.flash_error(msg) - if field == 'current_password': - self.ui.current_password_lineedit.setFocus() + self.ui.current_password_lineedit.setFocus() @QtCore.Slot() def _soledad_change_password_ok(self): diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index e18be976..f1252301 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -59,7 +59,7 @@ class PreferencesWindow(QtGui.QDialog): self.ui = Ui_Preferences() self.ui.setupUi(self) - self.ui.close_button.clicked.connect(self.close_window) + self.ui.close_button.clicked.connect(self.close) self.ui.account_label.setText(account.address) self.app.service_selection_changed.connect(self._update_icons) @@ -129,26 +129,20 @@ class PreferencesWindow(QtGui.QDialog): self.ui.pages_widget.addWidget(self._vpn_page) self.ui.pages_widget.addWidget(self._email_page) - def closeEvent(self, e): - """ - Override closeEvent to capture when user closes the window. - """ - self.close_window() - # # Slots # - @QtCore.Slot() - def close_window(self): + def closeEvent(self, e): """ TRIGGERS: self.ui.close_button.clicked + (since self.close() will trigger closeEvent) + whenever the window is closed Close this dialog and destroy it. """ PreferencesWindow._current_window = None - self.close() # deleteLater does not seem to cascade to items in stackLayout # (even with QtCore.Qt.WA_DeleteOnClose attribute). -- cgit v1.2.3 From 668a9f9aa327c3c055b9e0f641f8c33d59e1c452 Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 22 Sep 2014 09:56:48 -0700 Subject: country flags: add default fallback xx.png flag. --- data/images/countries/xx.png | Bin 0 -> 254 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/images/countries/xx.png diff --git a/data/images/countries/xx.png b/data/images/countries/xx.png new file mode 100644 index 00000000..abd36d39 Binary files /dev/null and b/data/images/countries/xx.png differ -- cgit v1.2.3 From d62b86224f1f4697c5c2a31d2cb0ad8b789fe1a9 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 22 Sep 2014 16:07:39 -0300 Subject: Use python2.7 instead of python2. The binary `python2` is not present on Debian systems. The common denominator for Ubuntu, Debian, Arch is `python2.7` Related to #6048. --- changes/bug_python2-compat | 1 + pkg/linux/bitmask-root | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/bug_python2-compat diff --git a/changes/bug_python2-compat b/changes/bug_python2-compat new file mode 100644 index 00000000..35331a36 --- /dev/null +++ b/changes/bug_python2-compat @@ -0,0 +1 @@ +- Use python2.7 since is the common name for python 2 in Ubuntu, Debian, Arch. Related to #6048. diff --git a/pkg/linux/bitmask-root b/pkg/linux/bitmask-root index 767dcc38..ee195e3b 100755 --- a/pkg/linux/bitmask-root +++ b/pkg/linux/bitmask-root @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python2.7 # -*- coding: utf-8 -*- # # Copyright (C) 2014 LEAP -- cgit v1.2.3 From be236a90af97c3b0f09f415e8d364b9e72f543f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 26 Sep 2014 10:06:36 -0300 Subject: Update relnotes --- relnotes.txt | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/relnotes.txt b/relnotes.txt index f2d28413..02e53ee6 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -1,8 +1,8 @@ -ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.6.1 +ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.7.0 The LEAP team is pleased to announce the immediate availability of version 0.6.1 of Bitmask, the Internet Encryption Toolkit, codename -"knock knock knocking on beta's door". +"one time download, all time updates". https://downloads.leap.se/client/ @@ -34,16 +34,14 @@ NOT trust your life to it. WHAT CAN THIS VERSION OF BITMASK DO FOR ME? -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 -OpenVPN, so use accordingly. You can refer to the CHANGELOG for the -meat. +Bitmask 0.7.0 brings with tremendous joy automatic and secure updates +through The Update Framework. Right beside TUF there are some bug +fixes and a new settings panel. -Encrypted Internet on Linux now avoids leaking traffic outside of -the secure connection it establishes. This will be added to other +You can read more about TUF in http://theupdateframework.com/ + +Encrypted Internet on Linux avoids leaking traffic outside of the +secure connection it establishes. This will be added to other platforms in the future. The Encrypted Mail services will run local SMTP and IMAP proxies that, @@ -90,7 +88,7 @@ You can send the bugs our way by pointing your telnet session to port our intensive bug-reeducation program. -LINUX ONLY: If you ever run into the situation where you cannot +LINUX ONLY: If you ever run into the situation where you cannot access internet, open the terminal and run the following command: $ pkexec /usr/local/sbin/bitmask-root firewall stop @@ -109,6 +107,6 @@ beyond any border. The LEAP team, -August 15, 2014 +Setptember 26, 2014 Somewhere in the middle of the intertubes. EOF -- cgit v1.2.3 From 5767efd10a2f794fe9367722bfb1ca114e63733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 26 Sep 2014 10:13:22 -0300 Subject: Fold in changes --- CHANGELOG.rst | 28 ++++++++++++++++++++++ changes/bug-5815_eip-preferences-issues | 2 -- changes/bug-5866_bitmask-lock-not-removed | 1 - changes/bug-5945_not-adding-helper-files | 1 - changes/bug-5995_save-provider-on-change | 1 - changes/bug-5996_update-eip-status-on-change | 1 - changes/bug-5997_get-ready-provider-on-change | 1 - changes/bug-6048_python2-bitmask-root | 1 - changes/bug-remove-dict-comprenhension | 1 - .../bug_5994_do-not-wait-for-eip-if-cannot-start | 1 - changes/bug_python2-compat | 1 - changes/bug_use_token_for_eip | 1 - changes/code-and-logging-cleanup | 1 - changes/feature-6040-email-firewall | 1 - changes/feature-6087_remove-AKM-menu | 2 -- changes/feature-combined-preferences-window | 1 - 16 files changed, 28 insertions(+), 17 deletions(-) delete mode 100644 changes/bug-5815_eip-preferences-issues delete mode 100644 changes/bug-5866_bitmask-lock-not-removed delete mode 100644 changes/bug-5945_not-adding-helper-files delete mode 100644 changes/bug-5995_save-provider-on-change delete mode 100644 changes/bug-5996_update-eip-status-on-change delete mode 100644 changes/bug-5997_get-ready-provider-on-change delete mode 100644 changes/bug-6048_python2-bitmask-root delete mode 100644 changes/bug-remove-dict-comprenhension delete mode 100644 changes/bug_5994_do-not-wait-for-eip-if-cannot-start delete mode 100644 changes/bug_python2-compat delete mode 100644 changes/bug_use_token_for_eip delete mode 100644 changes/code-and-logging-cleanup delete mode 100644 changes/feature-6040-email-firewall delete mode 100644 changes/feature-6087_remove-AKM-menu delete mode 100644 changes/feature-combined-preferences-window diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c47e531a..3c863657 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,34 @@ History 2014 ==== +0.7.0 September 26 -- the "one time download, all time updates" release: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +- Select current provider on EIP preferences. Closes #5815. +- Handle logout correctly when we stop_services to launch the + wizard. Related to #5815. +- Properly remove /tmp/bitmask.lock. Closes #5866. +- Hide EIP Start button and display correct warning on missing helpers + files. Closes #5945. +- Save default provider if changed on the combo box. Closes #5995. +- Update the EIP status on provider change. Closes #5996. +- Update and get ready to start a provider on change. Closes #5997. +- Use python2 to run bitmask-root to work fine on systems with python3 + as default. Closes #6048. +- Use python2.7 in bitmask-root shebang since is the common name for + python 2 in Ubuntu, Debian, Arch. Related to #6048. +- Remove dict comprenension in util, for 2.6 compat. +- Login shall not wait for eip to finish if eip is not able to + start. Closes #5994 +- Properly send the token for querying the EIP certificate. Fixes + #6060. +- Code cleanup and logging improvements. +- Add email firewall blocking other users to access bitmask imap & + smtp. Closes #6040 +- Remove the Advanced Key Management since we don't support stable + mail yet. Closes #6087. +- Single combined preferences window. Closes #4704, #4119, #5885. + 0.6.1 August 15 -- the "knock knock knocking on beta's door" release: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/changes/bug-5815_eip-preferences-issues b/changes/bug-5815_eip-preferences-issues deleted file mode 100644 index 013fe03d..00000000 --- a/changes/bug-5815_eip-preferences-issues +++ /dev/null @@ -1,2 +0,0 @@ -- Select current provider on EIP preferences. Closes #5815. -- Handle logout correctly when we stop_services to launch the wizard. Related to #5815. diff --git a/changes/bug-5866_bitmask-lock-not-removed b/changes/bug-5866_bitmask-lock-not-removed deleted file mode 100644 index d68c1122..00000000 --- a/changes/bug-5866_bitmask-lock-not-removed +++ /dev/null @@ -1 +0,0 @@ -- /tmp/bitmask.lock not removed. Closes #5866. diff --git a/changes/bug-5945_not-adding-helper-files b/changes/bug-5945_not-adding-helper-files deleted file mode 100644 index 94e41c25..00000000 --- a/changes/bug-5945_not-adding-helper-files +++ /dev/null @@ -1 +0,0 @@ -- Hide button and display correct warning on missing helpers files. Closes #5945. diff --git a/changes/bug-5995_save-provider-on-change b/changes/bug-5995_save-provider-on-change deleted file mode 100644 index e0f86d75..00000000 --- a/changes/bug-5995_save-provider-on-change +++ /dev/null @@ -1 +0,0 @@ -- Save default provider if changed on the combo box. Closes #5995. diff --git a/changes/bug-5996_update-eip-status-on-change b/changes/bug-5996_update-eip-status-on-change deleted file mode 100644 index 665092f0..00000000 --- a/changes/bug-5996_update-eip-status-on-change +++ /dev/null @@ -1 +0,0 @@ -- Update the EIP status on provider change. Closes #5996. diff --git a/changes/bug-5997_get-ready-provider-on-change b/changes/bug-5997_get-ready-provider-on-change deleted file mode 100644 index e6b3f7f1..00000000 --- a/changes/bug-5997_get-ready-provider-on-change +++ /dev/null @@ -1 +0,0 @@ -- Update and get ready to start a provider on change. Closes #5997. diff --git a/changes/bug-6048_python2-bitmask-root b/changes/bug-6048_python2-bitmask-root deleted file mode 100644 index 038196b0..00000000 --- a/changes/bug-6048_python2-bitmask-root +++ /dev/null @@ -1 +0,0 @@ -- Use python2 to run bitmask-root to work fine on systems with python3 as default. Closes #6048. diff --git a/changes/bug-remove-dict-comprenhension b/changes/bug-remove-dict-comprenhension deleted file mode 100644 index 4e9468d8..00000000 --- a/changes/bug-remove-dict-comprenhension +++ /dev/null @@ -1 +0,0 @@ -- Remove dict comprenension in util, for 2.6 compat. diff --git a/changes/bug_5994_do-not-wait-for-eip-if-cannot-start b/changes/bug_5994_do-not-wait-for-eip-if-cannot-start deleted file mode 100644 index 7ada612a..00000000 --- a/changes/bug_5994_do-not-wait-for-eip-if-cannot-start +++ /dev/null @@ -1 +0,0 @@ -- Login shall not wait for eip to finish if eip is not able to start. Closes: #5994 diff --git a/changes/bug_python2-compat b/changes/bug_python2-compat deleted file mode 100644 index 35331a36..00000000 --- a/changes/bug_python2-compat +++ /dev/null @@ -1 +0,0 @@ -- Use python2.7 since is the common name for python 2 in Ubuntu, Debian, Arch. Related to #6048. diff --git a/changes/bug_use_token_for_eip b/changes/bug_use_token_for_eip deleted file mode 100644 index b10368ad..00000000 --- a/changes/bug_use_token_for_eip +++ /dev/null @@ -1 +0,0 @@ -- Properly send the token for querying the EIP certificate. Fixes #6060. \ No newline at end of file diff --git a/changes/code-and-logging-cleanup b/changes/code-and-logging-cleanup deleted file mode 100644 index 3a381e68..00000000 --- a/changes/code-and-logging-cleanup +++ /dev/null @@ -1 +0,0 @@ -- Code cleanup and logging improvements. diff --git a/changes/feature-6040-email-firewall b/changes/feature-6040-email-firewall deleted file mode 100644 index 5ef70d28..00000000 --- a/changes/feature-6040-email-firewall +++ /dev/null @@ -1 +0,0 @@ -- Add email firewall blocking other users to access bitmask imap & smtp. Closes #6040 diff --git a/changes/feature-6087_remove-AKM-menu b/changes/feature-6087_remove-AKM-menu deleted file mode 100644 index 9326ca47..00000000 --- a/changes/feature-6087_remove-AKM-menu +++ /dev/null @@ -1,2 +0,0 @@ -- Remove the Advanced Key Management since we don't support stable mail yet. - Closes #6087. diff --git a/changes/feature-combined-preferences-window b/changes/feature-combined-preferences-window deleted file mode 100644 index 146ac923..00000000 --- a/changes/feature-combined-preferences-window +++ /dev/null @@ -1 +0,0 @@ -- single combined preferences window (closes #4704, #4119, #5885) \ No newline at end of file -- cgit v1.2.3 From 0db3d5a4aecc0a3c271b92c6187922c50d46df0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 26 Sep 2014 10:13:44 -0300 Subject: Revert "Fix soledad imports (#5989)." This reverts commit 7fcc4f40eaa8214de8ae20cd71d173337ad64290. --- changes/bug_5989_fix-soledad-imports | 1 - src/leap/bitmask/backend/components.py | 2 +- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 changes/bug_5989_fix-soledad-imports diff --git a/changes/bug_5989_fix-soledad-imports b/changes/bug_5989_fix-soledad-imports deleted file mode 100644 index 3b425287..00000000 --- a/changes/bug_5989_fix-soledad-imports +++ /dev/null @@ -1 +0,0 @@ -- Fix soledad imports (#5989). diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index d4f6d176..5ef6befd 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -60,7 +60,7 @@ from leap.common import certs as leap_certs from leap.keymanager import openpgp from leap.keymanager.errors import KeyAddressMismatch, KeyFingerprintMismatch -from leap.soledad.client.secrets import NoStorageSecret, PassphraseTooShort +from leap.soledad.client import NoStorageSecret, PassphraseTooShort logger = logging.getLogger(__name__) diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index 745645f3..c4e43bfe 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -45,8 +45,7 @@ from leap.common.files import which from leap.keymanager import KeyManager, openpgp from leap.keymanager.errors import KeyNotFound from leap.soledad.common.errors import InvalidAuthTokenError -from leap.soledad.client import Soledad -from leap.soledad.client.secrets import BootstrapSequenceError +from leap.soledad.client import Soledad, BootstrapSequenceError logger = logging.getLogger(__name__) -- cgit v1.2.3