From 4e5731c58becec8043cb2de5c3b9214f1f8cc849 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 4 Nov 2013 19:26:15 -0300 Subject: Support html logs in the logger window. Escape special characters to display them correctly in the logger window. [Closes #4146] --- src/leap/bitmask/gui/loggerwindow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/loggerwindow.py index ad2ceded..6ef58558 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/loggerwindow.py @@ -19,6 +19,7 @@ History log window """ import logging +import cgi from PySide import QtGui @@ -90,7 +91,7 @@ class LoggerWindow(QtGui.QDialog): logging.CRITICAL: "background: red; color: white; font: bold;" } level = log[LeapLogHandler.RECORD_KEY].levelno - message = log[LeapLogHandler.MESSAGE_KEY] + message = cgi.escape(log[LeapLogHandler.MESSAGE_KEY]) if self._logs_to_display[level]: open_tag = "" -- cgit v1.2.3 From 104c48b6eb3d6c2a092fae4d50ddd54d0130609b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 5 Nov 2013 14:10:33 -0300 Subject: Move string encoding to srpregister. --- src/leap/bitmask/crypto/srpregister.py | 3 ++- src/leap/bitmask/gui/wizard.py | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py index 5c0a8efc..61f1899a 100644 --- a/src/leap/bitmask/crypto/srpregister.py +++ b/src/leap/bitmask/crypto/srpregister.py @@ -108,7 +108,8 @@ class SRPRegister(QtCore.QObject): :rparam: (ok, request) """ - username = username.lower() + username = username.lower().encode('utf-8') + password = password.encode('utf-8') salt, verifier = self._srp.create_salted_verification_key( username, diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 6ba65410..e9c1d86c 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -226,9 +226,7 @@ class Wizard(QtGui.QWizard): self._registration_finished) threads.deferToThread( - partial(register.register_user, - username.encode("utf8"), - password.encode("utf8"))) + partial(register.register_user, username, password)) self._username = username self._password = password -- cgit v1.2.3 From 5ae44d80876aa9c1e60280fbf437ee687d9bc3c8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 5 Nov 2013 14:59:30 -0300 Subject: Handle Timeout errors during register. Also catch all request exceptions to avoid failures. [Closes #4358] --- src/leap/bitmask/crypto/srpregister.py | 3 +-- src/leap/bitmask/gui/wizard.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py index 61f1899a..e110df68 100644 --- a/src/leap/bitmask/crypto/srpregister.py +++ b/src/leap/bitmask/crypto/srpregister.py @@ -141,8 +141,7 @@ class SRPRegister(QtCore.QObject): verify=self._provider_config. get_ca_cert_path()) - except (requests.exceptions.SSLError, - requests.exceptions.ConnectionError) as exc: + except requests.exceptions.RequestExceptions as exc: logger.error(exc.message) ok = False else: diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index e9c1d86c..8de5802e 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -280,7 +280,8 @@ class Wizard(QtGui.QWizard): old_username = self._username self._username = None self._password = None - error_msg = self.tr("Unknown error") + error_msg = self.tr("Something has gone wrong. " + "Please try again.") try: content, _ = get_content(req) json_content = json.loads(content) -- cgit v1.2.3 From ac5c63a2636b1f764633283d18f04e0fc63a7b4f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 5 Nov 2013 15:20:16 -0300 Subject: Fix typo --- src/leap/bitmask/crypto/srpregister.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py index e110df68..02a1ea63 100644 --- a/src/leap/bitmask/crypto/srpregister.py +++ b/src/leap/bitmask/crypto/srpregister.py @@ -141,7 +141,7 @@ class SRPRegister(QtCore.QObject): verify=self._provider_config. get_ca_cert_path()) - except requests.exceptions.RequestExceptions as exc: + except requests.exceptions.RequestException as exc: logger.error(exc.message) ok = False else: -- cgit v1.2.3 From f04c992c2d06185aaca3f06bcb72a434fae33acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Wed, 6 Nov 2013 11:18:49 -0300 Subject: Various minor OSX fixes --- src/leap/bitmask/gui/mainwindow.py | 10 ++++------ src/leap/bitmask/gui/statemachines.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 5eb9e6dc..549097ae 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -334,7 +334,7 @@ class MainWindow(QtGui.QMainWindow): self.eip_machine = None # start event machines self.start_eip_machine() - self._mail_conductor.start_mail_machine(parent=self) + self._mail_conductor.start_mail_machine() if self._first_run(): self._wizard_firstrun = True @@ -674,10 +674,9 @@ class MainWindow(QtGui.QMainWindow): Toggles the window visibility """ visible = self.isVisible() and self.isActiveWindow() - qApp = QtCore.QCoreApplication.instance() if not visible: - qApp.setQuitOnLastWindowClosed(True) + QtGui.QApplication.setQuitOnLastWindowClosed(True) self.show() self.activateWindow() self.raise_() @@ -685,7 +684,7 @@ class MainWindow(QtGui.QMainWindow): # We set this in order to avoid dialogs shutting down the # app on close, as they will be the only visible window. # e.g.: PreferencesWindow, LoggerWindow - qApp.setQuitOnLastWindowClosed(False) + QtGui.QApplication.setQuitOnLastWindowClosed(False) self.hide() # Wait a bit until the window visibility has changed so @@ -1657,8 +1656,7 @@ class MainWindow(QtGui.QMainWindow): # UI stuff. # Set this in case that the app is hidden - qApp = QtCore.QCoreApplication.instance() - qApp.setQuitOnLastWindowClosed(True) + QtGui.QApplication.setQuitOnLastWindowClosed(True) self._cleanup_and_quit() diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py index 386cb75f..93731ce0 100644 --- a/src/leap/bitmask/gui/statemachines.py +++ b/src/leap/bitmask/gui/statemachines.py @@ -357,7 +357,7 @@ class ConnectionMachineBuilder(object): parent = kwargs.get('parent', None) # 1. create machine - machine = CompositeMachine(parent=parent) + machine = CompositeMachine() # 2. create states off = States.Off(conn.qtsigs.disconnected_signal, -- cgit v1.2.3 From 768bdfa653e7ef9829f355822ee0273072520c5f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Nov 2013 13:00:13 -0300 Subject: Fix 'cancel' and 'back' misbehavior. - Check if the 'next' button should be enabled after 'cancel' or 'back'. - Also, when the radio button is switched from existing to new provider, check if we need to enable the 'check' button. [Closes #4148] --- src/leap/bitmask/gui/wizard.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 8de5802e..5c4a6f8e 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -111,8 +111,9 @@ class Wizard(QtGui.QWizard): self.currentIdChanged.connect(self._current_id_changed) - self.ui.lnProvider.textChanged.connect( - self._enable_check) + self.ui.lnProvider.textChanged.connect(self._enable_check) + self.ui.rbNewProvider.toggled.connect( + lambda x: self._enable_check()) self.ui.lblUser.returnPressed.connect( self._focus_password) @@ -193,8 +194,19 @@ class Wizard(QtGui.QWizard): def get_services(self): return self._selected_services - def _enable_check(self, text): - self.ui.btnCheck.setEnabled(len(self.ui.lnProvider.text()) != 0) + @QtCore.Slot() + def _enable_check(self): + """ + SLOT + TRIGGER: + self.ui.lnProvider.textChanged + + Enables/disables the 'check' button in the SELECT_PROVIDER_PAGE + depending on the lnProvider content. + """ + enabled = len(self.ui.lnProvider.text()) != 0 + enabled = enabled and self.ui.rbNewProvider.isChecked() + self.ui.btnCheck.setEnabled(enabled) self._reset_provider_check() def _focus_password(self): @@ -555,8 +567,9 @@ class Wizard(QtGui.QWizard): Prepares the pages when they appear """ if pageId == self.SELECT_PROVIDER_PAGE: - self._reset_provider_check() - self._enable_check("") + skip = self.ui.rbExistingProvider.isChecked() + self._enable_check() + self._skip_provider_checks(skip) if pageId == self.SETUP_PROVIDER_PAGE: self._reset_provider_setup() -- cgit v1.2.3 From 1899d12a134d7657a902bd9d4006098a98e02277 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Nov 2013 15:20:44 -0300 Subject: Add hint about the duration of key generation. [Closes #3958] --- src/leap/bitmask/gui/mail_status.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index c1e82d4d..d637fd52 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -296,7 +296,9 @@ class MailStatusWidget(QtGui.QWidget): # elif req.event == proto.KEYMANAGER_KEY_NOT_FOUND: # ext_status = self.tr("Key not found!") elif req.event == proto.KEYMANAGER_STARTED_KEY_GENERATION: - ext_status = self.tr("Generating new key, please wait...") + ext_status = self.tr( + "Generating new key, please wait... \n" + "(this may take up to 10 minutes depending on the machine)") elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION: ext_status = self.tr("Finished generating key!") elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS: -- cgit v1.2.3 From 5955b267cdb6e82c57bee74a66ba8fa3d5308c60 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 6 Nov 2013 11:15:34 -0200 Subject: Initializes mail service with the user id. This will be used to properly obtain the private key that now is a property. It will also be needed for the imap authentication. --- src/leap/bitmask/gui/mainwindow.py | 18 ++++++++------- src/leap/bitmask/services/mail/conductor.py | 35 ++++++++++++++++------------- 2 files changed, 30 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 5eb9e6dc..2e050d44 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -905,7 +905,6 @@ class MainWindow(QtGui.QMainWindow): Once the user is properly authenticated, try starting the EIP service """ - # In general we want to "filter" likely complicated error # messages, but in this case, the messages make more sense as # they come. Since they are "Unknown user" or "Unknown @@ -914,19 +913,20 @@ class MainWindow(QtGui.QMainWindow): if ok: self._logged_user = self._login_widget.get_user() - # We leave a bit of room for the user to see the - # "Succeeded" message and then we switch to the EIP status - # panel - QtCore.QTimer.singleShot(1000, self._switch_to_status) + user = self._logged_user + domain = self._provider_config.get_domain() + userid = "%s@%s" % (user, domain) + logger.debug("USERID: " % userid) + self._mail_conductor.userid = userid self._login_defer = None + self._start_eip_bootstrap() else: self._login_widget.set_enabled(True) - def _switch_to_status(self): - # TODO this method name is confusing as hell. + def _start_eip_bootstrap(self): """ Changes the stackedWidget index to the EIP status one and - triggers the eip bootstrapping + triggers the eip bootstrapping. """ self._login_widget.logged_in() @@ -949,6 +949,8 @@ class MainWindow(QtGui.QMainWindow): else: self._mail_status.set_disabled() + # XXX the config should be downloaded from the start_eip + # method. self._download_eip_config() ################################################################### diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index c294381b..4d34a13b 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -81,16 +81,12 @@ class IMAPControl(object): "We need a non-null keymanager for initializing imap " "service") - if self.imap_service is None: - # first time. - self.imap_service, \ - self.imap_port, \ + self.imap_service, self.imap_port, \ self.imap_factory = imap.start_imap_service( self._soledad, - self._keymanager) - else: - # we have the fetcher. just start it. - self.imap_service.start_loop() + self._keymanager, + userid=self.userid) + self.imap_service.start_loop() def stop_imap_service(self): """ @@ -339,11 +335,25 @@ class MailConductor(IMAPControl, SMTPControl): SMTPControl.__init__(self) self._soledad = soledad self._keymanager = keymanager - self._mail_machine = None - self._mail_connection = mail_connection.MailConnection() + self.userid = None + + @property + def userid(self): + return self._userid + + @userid.setter + def _userid(self, userid): + """ + Sets the user id this conductor is configured for. + + :param userid: the user id, in the form "user@provider" + :type userid: str + """ + self._userid = userid + def start_mail_machine(self, **kwargs): """ Starts mail machine. @@ -354,15 +364,10 @@ class MailConductor(IMAPControl, SMTPControl): # we have instantiated the connections while building the composite # machines, and we have to use the qtsigs instantiated there. - # XXX we could probably use a proxy here too to make the thing - # transparent. self.set_imap_connection(imap.conn) self.set_smtp_connection(smtp.conn) self._mail_machine = mail - # XXX ------------------- - # need to keep a reference? - #self._mail_events = mail.events self._mail_machine.start() self._imap_machine = imap -- cgit v1.2.3 From 276810a3767fdba5e3ba543b23afc49f050b46b0 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Nov 2013 17:50:42 -0300 Subject: Remember setup provider checks. Also, on finish: - hide checks groupBox - clear domain lineEdit [Closes #3815] --- src/leap/bitmask/gui/wizard.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 5c4a6f8e..8508067e 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -147,6 +147,24 @@ class Wizard(QtGui.QWizard): self._load_configured_providers() + self._provider_checks_ok = False + self.finished.connect(self._wizard_finished) + + @QtCore.Slot() + def _wizard_finished(self): + """ + SLOT + TRIGGER: + self.finished + + This method is called when the wizard is accepted or rejected. + Here we do the cleanup needed to use the wizard again reusing the + instance. + """ + self._provider_checks_ok = False + self.ui.lnProvider.setText('') + self.ui.grpCheckProvider.setVisible(False) + def _load_configured_providers(self): """ Loads the configured providers into the wizard providers combo box. @@ -195,7 +213,7 @@ class Wizard(QtGui.QWizard): return self._selected_services @QtCore.Slot() - def _enable_check(self): + def _enable_check(self, reset=True): """ SLOT TRIGGER: @@ -207,7 +225,9 @@ class Wizard(QtGui.QWizard): enabled = len(self.ui.lnProvider.text()) != 0 enabled = enabled and self.ui.rbNewProvider.isChecked() self.ui.btnCheck.setEnabled(enabled) - self._reset_provider_check() + + if reset: + self._reset_provider_check() def _focus_password(self): """ @@ -350,6 +370,8 @@ class Wizard(QtGui.QWizard): if len(self.ui.lnProvider.text()) == 0: return + self._provider_checks_ok = False + self.ui.grpCheckProvider.setVisible(True) self.ui.btnCheck.setEnabled(False) self.ui.lnProvider.setEnabled(False) @@ -459,6 +481,7 @@ class Wizard(QtGui.QWizard): "provider.json")): self._complete_task(data, self.ui.lblProviderInfo, True, self.SELECT_PROVIDER_PAGE) + self._provider_checks_ok = True else: new_data = { self._provider_bootstrapper.PASSED_KEY: False, @@ -568,8 +591,11 @@ class Wizard(QtGui.QWizard): """ if pageId == self.SELECT_PROVIDER_PAGE: skip = self.ui.rbExistingProvider.isChecked() - self._enable_check() - self._skip_provider_checks(skip) + if not self._provider_checks_ok: + self._enable_check() + self._skip_provider_checks(skip) + else: + self._enable_check(reset=False) if pageId == self.SETUP_PROVIDER_PAGE: self._reset_provider_setup() -- cgit v1.2.3 From 9674b93f9d6fbe25e10330a6f807e5b7196c01b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Wed, 6 Nov 2013 11:54:03 -0300 Subject: Reject sender if it's not the logged in user --- src/leap/bitmask/gui/mainwindow.py | 1 - src/leap/bitmask/services/mail/conductor.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a91f4e71..91bbe9cb 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -915,7 +915,6 @@ class MainWindow(QtGui.QMainWindow): user = self._logged_user domain = self._provider_config.get_domain() userid = "%s@%s" % (user, domain) - logger.debug("USERID: " % userid) self._mail_conductor.userid = userid self._login_defer = None self._start_eip_bootstrap() diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index 4d34a13b..6dcf0c6f 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -200,6 +200,7 @@ class SMTPControl(object): from leap.mail.smtp import setup_smtp_relay self._smtp_service, self._smtp_port = setup_smtp_relay( port=2013, + userid=self.userid, keymanager=self._keymanager, smtp_host=host, smtp_port=port, @@ -345,7 +346,7 @@ class MailConductor(IMAPControl, SMTPControl): return self._userid @userid.setter - def _userid(self, userid): + def userid(self, userid): """ Sets the user id this conductor is configured for. -- cgit v1.2.3 From fb0d8da17541c48ed20d829d706e4cd9d3b4dde6 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 7 Nov 2013 09:38:28 -0300 Subject: Remember provider CA checks. [Closes #3814] --- src/leap/bitmask/gui/wizard.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 8508067e..5f5224ae 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -148,6 +148,7 @@ class Wizard(QtGui.QWizard): self._load_configured_providers() self._provider_checks_ok = False + self._provider_setup_ok = False self.finished.connect(self._wizard_finished) @QtCore.Slot() @@ -162,6 +163,7 @@ class Wizard(QtGui.QWizard): instance. """ self._provider_checks_ok = False + self._provider_setup_ok = False self.ui.lnProvider.setText('') self.ui.grpCheckProvider.setVisible(False) @@ -372,6 +374,10 @@ class Wizard(QtGui.QWizard): self._provider_checks_ok = False + # just in case that the user has already setup a provider and + # go 'back' to check a provider + self._provider_setup_ok = False + self.ui.grpCheckProvider.setVisible(True) self.ui.btnCheck.setEnabled(False) self.ui.lnProvider.setEnabled(False) @@ -533,6 +539,7 @@ class Wizard(QtGui.QWizard): """ self._complete_task(data, self.ui.lblCheckApiCert, True, self.SETUP_PROVIDER_PAGE) + self._provider_setup_ok = True def _service_selection_changed(self, service, state): """ @@ -598,14 +605,14 @@ class Wizard(QtGui.QWizard): self._enable_check(reset=False) if pageId == self.SETUP_PROVIDER_PAGE: - self._reset_provider_setup() - self.page(pageId).setSubTitle(self.tr("Gathering configuration " - "options for %s") % - (self._provider_config - .get_name(),)) - self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) - self._provider_setup_defer = self._provider_bootstrapper.\ - run_provider_setup_checks(self._provider_config) + if not self._provider_setup_ok: + self._reset_provider_setup() + sub_title = self.tr("Gathering configuration options for {0}") + sub_title = sub_title.format(self._provider_config.get_name()) + self.page(pageId).setSubTitle(sub_title) + self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) + self._provider_setup_defer = self._provider_bootstrapper.\ + run_provider_setup_checks(self._provider_config) if pageId == self.PRESENT_PROVIDER_PAGE: self.page(pageId).setSubTitle(self.tr("Description of services " -- cgit v1.2.3 From 540734c3aaffcdcd9140f0f6f723a7fac4ab18f0 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 8 Nov 2013 16:04:19 -0300 Subject: Use module attributes to store services strings. --- src/leap/bitmask/services/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/services/__init__.py b/src/leap/bitmask/services/__init__.py index e62277b6..ba12ba4e 100644 --- a/src/leap/bitmask/services/__init__.py +++ b/src/leap/bitmask/services/__init__.py @@ -37,7 +37,9 @@ from leap.common.files import get_mtime logger = logging.getLogger(__name__) -DEPLOYED = ["openvpn", "mx"] +EIP_SERVICE = u"openvpn" +MX_SERVICE = u"mx" +DEPLOYED = [EIP_SERVICE, MX_SERVICE] def get_service_display_name(service): -- cgit v1.2.3 From f3217d074ff20e6973ec382ad78100c77c6af081 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 8 Nov 2013 11:24:13 -0300 Subject: Use display service name instead of hardcode it. --- src/leap/bitmask/gui/eip_status.py | 11 +++++++---- src/leap/bitmask/gui/mail_status.py | 10 +++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 324586c0..fbb8ffe1 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -26,6 +26,7 @@ from PySide import QtCore, QtGui from leap.bitmask.services.eip.connection import EIPConnection from leap.bitmask.services.eip.vpnprocess import VPNManager +from leap.bitmask.services import get_service_display_name, EIP_SERVICE from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.util.averages import RateMovingAverage from leap.common.check import leap_assert_type @@ -58,6 +59,7 @@ class EIPStatusWidget(QtGui.QWidget): # set systray tooltip status self._eip_status = "" + self._service_name = get_service_display_name(EIP_SERVICE) self.ui.eip_bandwidth.hide() @@ -245,7 +247,7 @@ class EIPStatusWidget(QtGui.QWidget): # probably the best thing would be to make a transitional # transition there, but that's more involved. self.eip_button.hide() - msg = self.tr("You must login to use Encrypted Internet") + msg = self.tr("You must login to use {0}".format(self._service_name)) self.eip_label.setText(msg) @QtCore.Slot() @@ -418,14 +420,15 @@ class EIPStatusWidget(QtGui.QWidget): """ selected_pixmap = self.ERROR_ICON selected_pixmap_tray = self.ERROR_ICON_TRAY - tray_message = self.tr("Encrypted Internet: OFF") + tray_message = self.tr("{0}: OFF".format(self._service_name)) if status in ("WAIT", "AUTH", "GET_CONFIG", "RECONNECTING", "ASSIGN_IP"): selected_pixmap = self.CONNECTING_ICON selected_pixmap_tray = self.CONNECTING_ICON_TRAY - tray_message = self.tr("Encrypted Internet: Starting...") + tray_message = self.tr("{0}: Starting...").format( + self._service_name) elif status in ("CONNECTED"): - tray_message = self.tr("Encrypted Internet: ON") + tray_message = self.tr("{0}: ON".format(self._service_name)) selected_pixmap = self.CONNECTED_ICON selected_pixmap_tray = self.CONNECTED_ICON_TRAY self._eip_status = 'ON' diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index d637fd52..2ca0fb0a 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -22,6 +22,7 @@ import logging from PySide import QtCore, QtGui from leap.bitmask.platform_init import IS_LINUX +from leap.bitmask.services import get_service_display_name, MX_SERVICE from leap.common.check import leap_assert, leap_assert_type from leap.common.events import register from leap.common.events import events_pb2 as proto @@ -58,6 +59,7 @@ class MailStatusWidget(QtGui.QWidget): # set systray tooltip status self._mx_status = "" + self._service_name = get_service_display_name(MX_SERVICE) # Set the Mail status icons self.CONNECTING_ICON = None @@ -213,7 +215,8 @@ class MailStatusWidget(QtGui.QWidget): icon = self.ERROR_ICON if ready == 0: self.ui.lblMailStatus.setText( - self.tr("You must be logged in to use encrypted email.")) + self.tr("You must be logged in to use {0}.").format( + self._service_name)) elif ready == 1: icon = self.CONNECTING_ICON self._mx_status = self.tr('Starting..') @@ -436,5 +439,6 @@ class MailStatusWidget(QtGui.QWidget): Displays the correct UI for the disabled state. """ self._disabled = True - self._set_mail_status( - self.tr("You must be logged in to use encrypted email."), -1) + status = self.tr("You must be logged in to use {0}.").format( + self._service_name) + self._set_mail_status(status, -1) -- cgit v1.2.3 From 6714b423a4ae879e23a82a60480387186e737ab1 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 7 Nov 2013 17:46:02 -0300 Subject: Use custom systray that ease the tooltip use. - Create a custom SysTray that allows us to set services tooltips independently. - Initialize tooltip with service name at start. - Update required service status on tooltip update. [Closes #3998] --- src/leap/bitmask/gui/eip_status.py | 17 ++++++------- src/leap/bitmask/gui/mail_status.py | 21 ++++++---------- src/leap/bitmask/gui/mainwindow.py | 4 ++- src/leap/bitmask/gui/systray.py | 49 +++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 src/leap/bitmask/gui/systray.py (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index fbb8ffe1..c41d9706 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -183,21 +183,22 @@ class EIPStatusWidget(QtGui.QWidget): def set_systray(self, systray): """ - Sets the systray object to use. + Sets the systray object to use and adds the service line for EIP. :param systray: Systray object :type systray: QtGui.QSystemTrayIcon """ leap_assert_type(systray, QtGui.QSystemTrayIcon) self._systray = systray - self._systray.setToolTip(self.tr("All services are OFF")) + eip_status = self.tr("{0}: OFF").format(self._service_name) + self._systray.set_service_tooltip(EIP_SERVICE, eip_status) def _update_systray_tooltip(self): """ - Updates the system tray icon tooltip using the eip and mx status. + Updates the system tray tooltip using the eip status. """ - status = self.tr("Encrypted Internet: {0}").format(self._eip_status) - self._systray.setToolTip(status) + eip_status = u"{0}: {1}".format(self._service_name, self._eip_status) + self._systray.set_service_tooltip(EIP_SERVICE, eip_status) def set_action_eip_startstop(self, action_eip_startstop): """ @@ -395,10 +396,8 @@ class EIPStatusWidget(QtGui.QWidget): # the UI won't update properly QtCore.QTimer.singleShot( 0, self.eipconnection.qtsigs.do_disconnect_signal) - QtCore.QTimer.singleShot(0, partial(self.set_eip_status, - self.tr("Unable to start VPN, " - "it's already " - "running."))) + msg = self.tr("Unable to start VPN, it's already running.") + QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg)) else: self.set_eip_status(status) diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index 2ca0fb0a..e89fb376 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -152,29 +152,22 @@ class MailStatusWidget(QtGui.QWidget): def set_systray(self, systray): """ - Sets the systray object to use. + Sets the systray object to use and adds the service line for MX. :param systray: Systray object :type systray: QtGui.QSystemTrayIcon """ leap_assert_type(systray, QtGui.QSystemTrayIcon) self._systray = systray - self._systray.setToolTip(self.tr("All services are OFF")) + mx_status = self.tr("{0}: OFF").format(self._service_name) + self._systray.set_service_tooltip(MX_SERVICE, mx_status) def _update_systray_tooltip(self): """ - Updates the system tray icon tooltip using the eip and mx status. - """ - # TODO: Figure out how to handle this with the two status in different - # classes - # XXX right now we could connect the state transition signals of the - # two connection machines (EIP/Mail) to a class that keeps track of the - # state -- kali - # status = self.tr("Encrypted Internet: {0}").format(self._eip_status) - # status += '\n' - # status += self.tr("Mail is {0}").format(self._mx_status) - # self._systray.setToolTip(status) - pass + Updates the system tray tooltip using the mx status. + """ + mx_status = u"{0}: {1}".format(self._service_name, self._mx_status) + self._systray.set_service_tooltip(MX_SERVICE, mx_status) def set_action_mail_status(self, action_mail_status): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 91bbe9cb..f7142df7 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -36,6 +36,7 @@ from leap.bitmask.gui import statemachines from leap.bitmask.gui.eip_status import EIPStatusWidget from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.wizard import Wizard +from leap.bitmask.gui.systray import SysTray from leap.bitmask import provider from leap.bitmask.platform_init import IS_WIN, IS_MAC @@ -628,12 +629,13 @@ class MainWindow(QtGui.QMainWindow): systrayMenu.addAction(self._action_mail_status) systrayMenu.addSeparator() systrayMenu.addAction(self.ui.action_quit) - self._systray = QtGui.QSystemTrayIcon(self) + self._systray = SysTray(self) self._systray.setContextMenu(systrayMenu) self._systray.setIcon(self._eip_status.ERROR_ICON_TRAY) self._systray.setVisible(True) self._systray.activated.connect(self._tray_activated) + self._mail_status.set_systray(self._systray) self._eip_status.set_systray(self._systray) def _tray_activated(self, reason=None): diff --git a/src/leap/bitmask/gui/systray.py b/src/leap/bitmask/gui/systray.py new file mode 100644 index 00000000..d30b5f32 --- /dev/null +++ b/src/leap/bitmask/gui/systray.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# systray.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Custom system tray manager. +""" + +from PySide import QtGui + +from leap.common.check import leap_assert_type + + +class SysTray(QtGui.QSystemTrayIcon): + """ + Custom system tray that allows us to use a more 'intelligent' tooltip. + """ + + def __init__(self, parent=None): + QtGui.QSystemTrayIcon.__init__(self, parent) + self._services = {} + + def set_service_tooltip(self, service, tooltip): + """ + Sets the service tooltip. + + :param service: service name identifier + :type service: unicode + :param tooltip: tooltip to display for that service + :type tooltip: unicode + """ + leap_assert_type(service, unicode) + leap_assert_type(tooltip, unicode) + + self._services[service] = tooltip + tooltip = "\n".join(self._services.values()) + self.setToolTip(tooltip) -- cgit v1.2.3 From 13470807d96cfb6e10bc647aab8111a2b61bb6ea Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 8 Nov 2013 16:37:48 -0300 Subject: Use service's module strings instead of locals. --- src/leap/bitmask/gui/mainwindow.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index f7142df7..f3043809 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -45,6 +45,7 @@ from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper from leap.bitmask.services.mail import conductor as mail_conductor +from leap.bitmask.services import EIP_SERVICE, MX_SERVICE from leap.bitmask.services.eip import eipconfig from leap.bitmask.services.eip import get_openvpn_management from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper @@ -87,9 +88,6 @@ class MainWindow(QtGui.QMainWindow): LOGIN_INDEX = 0 EIP_STATUS_INDEX = 1 - OPENVPN_SERVICE = "openvpn" - MX_SERVICE = "mx" - # Signals eip_needs_login = QtCore.Signal([]) new_updates = QtCore.Signal(object) @@ -598,8 +596,8 @@ class MainWindow(QtGui.QMainWindow): for service in provider_config.get_services(): services.add(service) - self.ui.eipWidget.setVisible(self.OPENVPN_SERVICE in services) - self.ui.mailWidget.setVisible(self.MX_SERVICE in services) + self.ui.eipWidget.setVisible(EIP_SERVICE in services) + self.ui.mailWidget.setVisible(MX_SERVICE in services) # # systray @@ -938,7 +936,7 @@ class MainWindow(QtGui.QMainWindow): # TODO separate UI from logic. # TODO soledad should check if we want to run only over EIP. if self._provider_config.provides_mx() and \ - self._enabled_services.count(self.MX_SERVICE) > 0: + self._enabled_services.count(MX_SERVICE) > 0: self._mail_status.about_to_start() self._soledad_bootstrapper.run_soledad_setup_checks( @@ -1039,7 +1037,7 @@ class MainWindow(QtGui.QMainWindow): # TODO for simmetry, this should be called start_smtp_service # (and delegate all the checks to the conductor) if self._provider_config.provides_mx() and \ - self._enabled_services.count(self.MX_SERVICE) > 0: + self._enabled_services.count(MX_SERVICE) > 0: self._mail_conductor.smtp_bootstrapper.run_smtp_setup_checks( self._provider_config, self._mail_conductor.smtp_config, @@ -1068,7 +1066,7 @@ class MainWindow(QtGui.QMainWindow): self.soledad_ready """ if self._provider_config.provides_mx() and \ - self._enabled_services.count(self.MX_SERVICE) > 0: + self._enabled_services.count(MX_SERVICE) > 0: self._mail_conductor.start_imap_service() def _on_mail_client_logged_in(self, req): @@ -1418,7 +1416,7 @@ class MainWindow(QtGui.QMainWindow): provider_config = self._get_best_provider_config() if provider_config.provides_eip() and \ - self._enabled_services.count(self.OPENVPN_SERVICE) > 0 and \ + self._enabled_services.count(EIP_SERVICE) > 0 and \ not self._already_started_eip: # XXX this should be handled by the state machine. @@ -1429,7 +1427,7 @@ class MainWindow(QtGui.QMainWindow): download_if_needed=True) self._already_started_eip = True elif not self._already_started_eip: - if self._enabled_services.count(self.OPENVPN_SERVICE) > 0: + if self._enabled_services.count(EIP_SERVICE) > 0: self._eip_status.set_eip_status( self.tr("Not supported"), error=True) -- cgit v1.2.3 From 6c5a431034cb423a69c8f58a16fbb39a37dec73c Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 8 Nov 2013 17:23:06 -0300 Subject: Check if we have a systray to use. This fixes a failure when we run the first run wizard and don't have a systray ready. --- src/leap/bitmask/gui/eip_status.py | 6 ++++-- src/leap/bitmask/gui/mail_status.py | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index c41d9706..1899d6a4 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -197,8 +197,10 @@ class EIPStatusWidget(QtGui.QWidget): """ Updates the system tray tooltip using the eip status. """ - eip_status = u"{0}: {1}".format(self._service_name, self._eip_status) - self._systray.set_service_tooltip(EIP_SERVICE, eip_status) + if self._systray is not None: + eip_status = u"{0}: {1}".format( + self._service_name, self._eip_status) + self._systray.set_service_tooltip(EIP_SERVICE, eip_status) def set_action_eip_startstop(self, action_eip_startstop): """ diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index e89fb376..ec8d8f20 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -166,8 +166,9 @@ class MailStatusWidget(QtGui.QWidget): """ Updates the system tray tooltip using the mx status. """ - mx_status = u"{0}: {1}".format(self._service_name, self._mx_status) - self._systray.set_service_tooltip(MX_SERVICE, mx_status) + if self._systray is not None: + mx_status = u"{0}: {1}".format(self._service_name, self._mx_status) + self._systray.set_service_tooltip(MX_SERVICE, mx_status) def set_action_mail_status(self, action_mail_status): """ -- cgit v1.2.3 From 59868c95c23e825544b2c986bf7fe6c15538bbe5 Mon Sep 17 00:00:00 2001 From: drebs Date: Thu, 7 Nov 2013 17:09:15 -0200 Subject: Fix call to smtp gateway. --- src/leap/bitmask/services/mail/conductor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index 6dcf0c6f..a9621b13 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -197,8 +197,8 @@ class SMTPControl(object): # TODO remove hard-coded port and let leap.mail set # the specific default. self.smtp_connection.qtsigs.connecting_signal.emit() - from leap.mail.smtp import setup_smtp_relay - self._smtp_service, self._smtp_port = setup_smtp_relay( + from leap.mail.smtp import setup_smtp_gateway + self._smtp_service, self._smtp_port = setup_smtp_gateway( port=2013, userid=self.userid, keymanager=self._keymanager, -- cgit v1.2.3 From e34674449f5423b07fed608f7c0d2a4e70e5ff4f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 11 Nov 2013 11:54:49 -0300 Subject: Show a more generic message to the user. --- src/leap/bitmask/gui/mail_status.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index ec8d8f20..3c933c9a 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -294,8 +294,7 @@ class MailStatusWidget(QtGui.QWidget): # ext_status = self.tr("Key not found!") elif req.event == proto.KEYMANAGER_STARTED_KEY_GENERATION: ext_status = self.tr( - "Generating new key, please wait... \n" - "(this may take up to 10 minutes depending on the machine)") + "Generating new key, this may take a few minutes.") elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION: ext_status = self.tr("Finished generating key!") elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS: -- cgit v1.2.3 From 02a72c675107f9d324184265e414600c69763d7a Mon Sep 17 00:00:00 2001 From: drebs Date: Mon, 11 Nov 2013 14:40:59 -0200 Subject: Send user's key to nickserver whenever the keymanager is initialized. --- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index 54ef67eb..ce8bf813 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -367,6 +367,8 @@ class SoledadBootstrapper(AbstractBootstrapper): api_version=self._provider_config.get_api_version(), uid=srp_auth.get_uid(), gpgbinary=self._get_gpg_bin_path()) + # make sure key is in server + self._keymanager.send_key(openpgp.OpenPGPKey) def _gen_key(self, _): """ @@ -393,7 +395,7 @@ class SoledadBootstrapper(AbstractBootstrapper): try: self._keymanager.gen_key(openpgp.OpenPGPKey) except Exception as exc: - logger.error("error while generating key!") + logger.error("Error while generating key!") logger.exception(exc) raise @@ -401,7 +403,7 @@ class SoledadBootstrapper(AbstractBootstrapper): try: self._keymanager.send_key(openpgp.OpenPGPKey) except Exception as exc: - logger.error("error while sending key!") + logger.error("Error while sending key!") logger.exception(exc) raise -- cgit v1.2.3 From 1fb82f0ad4a2a397e4b938748e58a64d057599e4 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 12 Nov 2013 13:39:26 -0200 Subject: deferToThread initial soledad sync --- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index 54ef67eb..c672c893 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -28,6 +28,8 @@ from PySide import QtCore from u1db import errors as u1db_errors from zope.proxy import sameProxiedObjects +from twisted.internet.threads import deferToThread + from leap.bitmask.config import flags from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth @@ -194,7 +196,12 @@ class SoledadBootstrapper(AbstractBootstrapper): leap_assert(not sameProxiedObjects(self._soledad, None), "Null soledad, error while initializing") + self.deferred = deferToThread(self._do_soledad_sync) + def _do_soledad_sync(self): + """ + Does several retries to get an initial soledad sync. + """ # and now, let's sync sync_tries = self.MAX_SYNC_RETRIES while sync_tries > 0: -- cgit v1.2.3 From 19df4a679664e76874e970813599c13c94dfd745 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 12 Nov 2013 23:28:17 -0200 Subject: re-raise the exceptions on init as expected --- src/leap/bitmask/services/mail/conductor.py | 2 +- src/leap/bitmask/services/soledad/soledadbootstrapper.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index a9621b13..addf9bef 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -98,6 +98,7 @@ class IMAPControl(object): logger.debug('Stopping imap service.') # Stop the loop call in the fetcher self.imap_service.stop() + self.imap_service = None # Stop listening on the IMAP port self.imap_port.stopListening() # Stop the protocol @@ -107,7 +108,6 @@ class IMAPControl(object): """ Fetches incoming mail. """ - # TODO have a mutex over fetch operation. if self.imap_service: logger.debug('Client connected, fetching mail...') self.imap_service.fetch() diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index c672c893..b046d279 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -207,10 +207,6 @@ class SoledadBootstrapper(AbstractBootstrapper): while sync_tries > 0: try: self._try_soledad_sync() - - # at this point, sometimes the client - # gets stuck and does not progress to - # the _gen_key step. XXX investigate. logger.debug("Soledad has been synced.") # so long, and thanks for all the fish return @@ -266,26 +262,32 @@ class SoledadBootstrapper(AbstractBootstrapper): except socket.timeout: logger.debug("SOLEDAD initialization TIMED OUT...") self.soledad_timeout.emit() + raise except socket.error as exc: logger.warning("Socket error while initializing soledad") self.soledad_timeout.emit() + raise except BootstrapSequenceError as exc: logger.warning("Error while initializing soledad") self.soledad_timeout.emit() + raise # unrecoverable except u1db_errors.Unauthorized: logger.error("Error while initializing soledad " "(unauthorized).") self.soledad_failed.emit() + raise except u1db_errors.HTTPError as exc: logger.exception("Error whie initializing soledad " "(HTTPError)") self.soledad_failed.emit() + raise except Exception as exc: logger.exception("Unhandled error while initializating " "soledad: %r" % (exc,)) self.soledad_failed.emit() + raise def _try_soledad_sync(self): """ @@ -299,9 +301,8 @@ class SoledadBootstrapper(AbstractBootstrapper): logger.error("%r" % (exc,)) raise SoledadSyncError("Failed to sync soledad") except Exception as exc: - logger.exception("Unhandled error while syncing" + logger.exception("Unhandled error while syncing " "soledad: %r" % (exc,)) - self.soledad_failed.emit() raise SoledadSyncError("Failed to sync soledad") def _download_config(self): -- cgit v1.2.3 From 223d17f74f59121875d2eb42c3a4e4d638ae2f08 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 13 Nov 2013 16:42:15 -0200 Subject: do not raise if error while syncing --- .../services/soledad/soledadbootstrapper.py | 37 +++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index 70318ab8..e8c7e9ce 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -364,19 +364,32 @@ class SoledadBootstrapper(AbstractBootstrapper): """ srp_auth = self.srpauth logger.debug('initializing keymanager...') - self._keymanager = KeyManager( - address, - "https://nicknym.%s:6425" % (self._provider_config.get_domain(),), - self._soledad, - #token=srp_auth.get_token(), # TODO: enable token usage - session_id=srp_auth.get_session_id(), - ca_cert_path=self._provider_config.get_ca_cert_path(), - api_uri=self._provider_config.get_api_uri(), - api_version=self._provider_config.get_api_version(), - uid=srp_auth.get_uid(), - gpgbinary=self._get_gpg_bin_path()) + try: + self._keymanager = KeyManager( + address, + "https://nicknym.%s:6425" % ( + self._provider_config.get_domain(),), + self._soledad, + #token=srp_auth.get_token(), # TODO: enable token usage + session_id=srp_auth.get_session_id(), + ca_cert_path=self._provider_config.get_ca_cert_path(), + api_uri=self._provider_config.get_api_uri(), + api_version=self._provider_config.get_api_version(), + uid=srp_auth.get_uid(), + gpgbinary=self._get_gpg_bin_path()) + except Exception as exc: + logger.exception(exc) + raise + + logger.debug('sending key to server...') + # make sure key is in server - self._keymanager.send_key(openpgp.OpenPGPKey) + try: + self._keymanager.send_key(openpgp.OpenPGPKey) + except Exception as exc: + logger.error("Error sending key to server.") + logger.exception(exc) + # but we do not raise def _gen_key(self, _): """ -- cgit v1.2.3 From 5273f6694bffbba0a07c34f19a5a6630382e4d48 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 11:34:46 -0300 Subject: Add advanced key management dialog. --- src/leap/bitmask/gui/advanced_key_management.py | 185 +++++++++++++++++++++ src/leap/bitmask/gui/ui/advanced_key_management.ui | 153 +++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 src/leap/bitmask/gui/advanced_key_management.py create mode 100644 src/leap/bitmask/gui/ui/advanced_key_management.ui (limited to 'src') diff --git a/src/leap/bitmask/gui/advanced_key_management.py b/src/leap/bitmask/gui/advanced_key_management.py new file mode 100644 index 00000000..2c0fa034 --- /dev/null +++ b/src/leap/bitmask/gui/advanced_key_management.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# advanced_key_management.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Advanced Key Management +""" +import logging + +from PySide import QtGui +from zope.proxy import sameProxiedObjects + +from leap.keymanager import openpgp +from leap.keymanager.errors import KeyAddressMismatch, KeyFingerprintMismatch +from leap.bitmask.services import get_service_display_name, MX_SERVICE +from ui_advanced_key_management import Ui_AdvancedKeyManagement + +logger = logging.getLogger(__name__) + + +class AdvancedKeyManagement(QtGui.QWidget): + """ + Advanced Key Management + """ + def __init__(self, user, keymanager, soledad): + """ + :param user: the current logged in user. + :type user: unicode + :param keymanager: the existing keymanager instance + :type keymanager: KeyManager + :param soledad: a loaded instance of Soledad + :type soledad: Soledad + """ + QtGui.QWidget.__init__(self) + + self.ui = Ui_AdvancedKeyManagement() + self.ui.setupUi(self) + + # if Soledad is not started yet + if sameProxiedObjects(soledad, None): + self.ui.container.setEnabled(False) + msg = self.tr("NOTE: " + "To use this, you need to enable/start {0}.") + msg = msg.format(get_service_display_name(MX_SERVICE)) + self.ui.lblStatus.setText(msg) + return + else: + msg = self.tr( + "WARNING:
" + "This is an experimental feature, you can lose access to " + "existing e-mails.") + self.ui.lblStatus.setText(msg) + + self._keymanager = keymanager + self._soledad = soledad + + self._key = keymanager.get_key(user, openpgp.OpenPGPKey) + self._key_priv = keymanager.get_key( + user, openpgp.OpenPGPKey, private=True) + + # show current key information + self.ui.leUser.setText(user) + self.ui.leKeyID.setText(self._key.key_id) + self.ui.leFingerprint.setText(self._key.fingerprint) + + # set up connections + self.ui.pbImportKeys.clicked.connect(self._import_keys) + self.ui.pbExportKeys.clicked.connect(self._export_keys) + + def _import_keys(self): + """ + Imports the user's key pair. + Those keys need to be ascii armored. + """ + fileName, filtr = QtGui.QFileDialog.getOpenFileName( + self, self.tr("Open keys file"), + options=QtGui.QFileDialog.DontUseNativeDialog) + + if fileName: + new_key = '' + try: + with open(fileName, 'r') as keys_file: + new_key = keys_file.read() + except IOError as e: + logger.error("IOError importing key. {0!r}".format(e)) + QtGui.QMessageBox.critical( + self, self.tr("Input/Output error"), + self.tr("There was an error accessing the file.\n" + "Import canceled.")) + return + + keymanager = self._keymanager + try: + public_key, private_key = keymanager.parse_openpgp_ascii_key( + new_key) + except (KeyAddressMismatch, KeyFingerprintMismatch) as e: + logger.error(repr(e)) + QtGui.QMessageBox.warning( + self, self.tr("Data mismatch"), + self.tr("The public and private key should have the " + "same address and fingerprint.\n" + "Import canceled.")) + return + + if public_key is None or private_key is None: + QtGui.QMessageBox.warning( + self, self.tr("Missing key"), + self.tr("You need to provide the public AND private " + "key in the same file.\n" + "Import canceled.")) + return + + if public_key.address != self._key.address: + logger.error("The key does not match the ID") + QtGui.QMessageBox.warning( + self, self.tr("Address mismatch"), + self.tr("The identity for the key needs to be the same " + "as your user address.\n" + "Import canceled.")) + return + + question = self.tr("Are you sure that you want to replace " + "the current key pair whith the imported?") + res = QtGui.QMessageBox.question( + None, "Change key pair", question, + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, + QtGui.QMessageBox.No) # default No + + if res == QtGui.QMessageBox.No: + return + + keymanager.delete_key(self._key) + keymanager.delete_key(self._key_priv) + keymanager.put_key(public_key) + keymanager.put_key(private_key) + keymanager.send_key(openpgp.OpenPGPKey) + + logger.debug('Import ok') + + QtGui.QMessageBox.information( + self, self.tr("Import Successful"), + self.tr("The key pair was imported successfully.")) + else: + logger.debug('Import canceled by the user.') + + def _export_keys(self): + """ + Exports the user's key pair. + """ + fileName, filtr = QtGui.QFileDialog.getSaveFileName( + self, self.tr("Save keys file"), + options=QtGui.QFileDialog.DontUseNativeDialog) + + if fileName: + try: + with open(fileName, 'w') as keys_file: + keys_file.write(self._key.key_data) + keys_file.write(self._key_priv.key_data) + + logger.debug('Export ok') + QtGui.QMessageBox.information( + self, self.tr("Export Successful"), + self.tr("The key pair was exported successfully.\n" + "Please, store your private key in a safe place.")) + except IOError as e: + logger.error("IOError exporting key. {0!r}".format(e)) + QtGui.QMessageBox.critical( + self, self.tr("Input/Output error"), + self.tr("There was an error accessing the file.\n" + "Export canceled.")) + return + else: + logger.debug('Export canceled by the user.') diff --git a/src/leap/bitmask/gui/ui/advanced_key_management.ui b/src/leap/bitmask/gui/ui/advanced_key_management.ui new file mode 100644 index 00000000..d61aa87e --- /dev/null +++ b/src/leap/bitmask/gui/ui/advanced_key_management.ui @@ -0,0 +1,153 @@ + + + AdvancedKeyManagement + + + + 0 + 0 + 431 + 188 + + + + Advanced Key Management + + + + :/images/mask-icon.png:/images/mask-icon.png + + + + + + + + + User: + + + + + + + true + + + user_name@provider + + + Qt::AlignCenter + + + true + + + + + + + Key ID: + + + + + + + true + + + key ID + + + Qt::AlignCenter + + + true + + + + + + + Key fingerprint: + + + + + + + true + + + fingerprint + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Export current key pair + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Import custom key pair + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 46a9bcbc1242aacad1947087c2d30c7952872d7b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 14:28:52 -0300 Subject: Set token to none in logout. --- src/leap/bitmask/crypto/srpauth.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index ab98850d..85b9b003 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -581,6 +581,7 @@ class SRPAuth(QtCore.QObject): else: self.set_session_id(None) self.set_uid(None) + self.set_token(None) # Also reset the session self._session = self._fetcher.session() logger.debug("Successfully logged out.") -- cgit v1.2.3 From b0b820d4dc579e3bf5bbfbe68c7911d573aea205 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 14:30:57 -0300 Subject: Use services' module names for the service. --- src/leap/bitmask/gui/preferenceswindow.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index acb39b07..3843ccde 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -22,7 +22,9 @@ import os import logging from functools import partial + from PySide import QtCore, QtGui +from zope.proxy import sameProxiedObjects from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.ui_preferences import Ui_Preferences @@ -31,7 +33,7 @@ from leap.bitmask.crypto.srpauth import SRPAuthBadUserOrPassword from leap.bitmask.util.password import basic_password_checks from leap.bitmask.services import get_supported from leap.bitmask.config.providerconfig import ProviderConfig -from leap.bitmask.services import get_service_display_name +from leap.bitmask.services import get_service_display_name, MX_SERVICE logger = logging.getLogger(__name__) @@ -81,12 +83,13 @@ class PreferencesWindow(QtGui.QDialog): # check if provider has 'mx' ... domain = provider_config.get_domain() self._select_provider_by_name(domain) + if provider_config.provides_mx(): enabled_services = self._settings.get_enabled_services(domain) - mx_name = get_service_display_name('mx') + mx_name = get_service_display_name(MX_SERVICE) # ... and if the user have it enabled - if 'mx' not in enabled_services: + 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) -- cgit v1.2.3 From 20d89634f7b891fb4f399da51b3800d42159b9eb Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 14:34:46 -0300 Subject: Enable password change in proper conditions. - Send soledad to the constructor and check with sameProxiedObjects - Check if soledad instance is defined, otherwise wait until soledad_ready [Closes #4449] --- src/leap/bitmask/gui/mainwindow.py | 7 +++---- src/leap/bitmask/gui/preferenceswindow.py | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index f3043809..c24735d8 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -446,11 +446,10 @@ class MainWindow(QtGui.QMainWindow): Displays the preferences window. """ preferences_window = PreferencesWindow(self, self._srp_auth, - self._provider_config) - - self.soledad_ready.connect( - lambda: preferences_window.set_soledad_ready(self._soledad)) + self._provider_config, + self._soledad) + self.soledad_ready.connect(preferences_window.set_soledad_ready) preferences_window.show() def _show_eip_preferences(self): diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 3843ccde..8e9ef95a 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -42,7 +42,7 @@ class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ - def __init__(self, parent, srp_auth, provider_config): + def __init__(self, parent, srp_auth, provider_config, soledad): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -50,13 +50,15 @@ class PreferencesWindow(QtGui.QDialog): :type srp_auth: SRPAuth :param provider_config: ProviderConfig object. :type provider_config: ProviderConfig + :param soledad: Soledad instance + :type soledad: Soledad """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = LeapSettings() - self._soledad = None + self._soledad = soledad # Load UI self.ui = Ui_Preferences() @@ -94,10 +96,14 @@ class PreferencesWindow(QtGui.QDialog): "the password.".format(mx_name)) self._set_password_change_status(msg, error=True) else: - 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) + if sameProxiedObjects(self._soledad, None): + 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) + else: + # Soledad is bootstrapped + pw_enabled = True else: pw_enabled = True else: @@ -107,18 +113,14 @@ class PreferencesWindow(QtGui.QDialog): self.ui.gbPasswordChange.setEnabled(pw_enabled) - def set_soledad_ready(self, soledad): + def set_soledad_ready(self): """ SLOT TRIGGERS: parent.soledad_ready - It sets the soledad object as ready to use. - - :param soledad: Soledad object configured in the main app. - :type soledad: Soledad + It notifies when the soledad object as ready to use. """ - self._soledad = soledad self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.gbPasswordChange.setEnabled(True) -- cgit v1.2.3 From ed08a7619bd79a594d579b4bfbc7d4bdce3ccd7a Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 11:39:41 -0300 Subject: Add the advanced key management to the main window --- src/leap/bitmask/gui/mainwindow.py | 19 +++++++++++++++++++ src/leap/bitmask/gui/ui/mainwindow.ui | 13 +++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index f3043809..39a08cfb 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -29,6 +29,7 @@ from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.gui.loggerwindow import LoggerWindow +from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement from leap.bitmask.gui.login import LoginWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow @@ -252,6 +253,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.action_create_new_account.triggered.connect( self._launch_wizard) + self.ui.action_advanced_key_management.triggered.connect( + self._show_AKM) + if IS_MAC: self.ui.menuFile.menuAction().setText(self.tr("File")) @@ -437,6 +441,20 @@ class MainWindow(QtGui.QMainWindow): else: self._logger_window.setVisible(not self._logger_window.isVisible()) + def _show_AKM(self): + """ + SLOT + TRIGGERS: + self.ui.action_advanced_key_management.triggered + + Displays the Advanced Key Management dialog. + """ + domain = self._login_widget.get_selected_provider() + logged_user = "{0}@{1}".format(self._logged_user, domain) + self._akm = AdvancedKeyManagement( + logged_user, self._keymanager, self._soledad) + self._akm.show() + def _show_preferences(self): """ SLOT @@ -1522,6 +1540,7 @@ class MainWindow(QtGui.QMainWindow): """ self._soledad_bootstrapper.cancel_bootstrap() + setProxiedObject(self._soledad, None) # XXX: If other defers are doing authenticated stuff, this # might conflict with those. CHECK! diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index badd291d..3b83788e 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -75,7 +75,7 @@ 0 0 524 - 636 + 651 @@ -380,7 +380,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb 0 0 524 - 22 + 21 @@ -388,6 +388,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb &Bitmask + @@ -439,6 +440,14 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb Create a new account... + + + true + + + Advanced Key Management + + -- cgit v1.2.3