From 247e9e68244054f8def6ca0b700b4f146f9ece39 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 4 Nov 2013 16:41:38 -0300 Subject: Add document with good practices for encoding. --- docs/dev/encodings.rst | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 65 insertions(+) create mode 100644 docs/dev/encodings.rst diff --git a/docs/dev/encodings.rst b/docs/dev/encodings.rst new file mode 100644 index 00000000..a3fc4b70 --- /dev/null +++ b/docs/dev/encodings.rst @@ -0,0 +1,64 @@ +.. _encodings: + +Strings encoding problems +========================= + +This document is meant to avoid ``UnicodeError`` (``UnicodeEncodeError`` , ``UnicodeDecodeError``) and to set a base that allows the users to keep away headaches. + + +First approach +-------------- + +One of the problems with python 2 that makes hard to find out problems is the implicit conversion between ``str`` and ``unicode``. + +Look at this code:: + + >>> u'ä'.encode('utf-8') + '\xc3\xa4' + >>> + >>> u'ä'.decode('utf-8') + Traceback (most recent call last): + File "", line 1, in + File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode + return codecs.utf_8_decode(input, errors, True) + UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 0: ordinal not in range(128) + +A situation like this could happen if the user confuse one type for another. 'encode' is a method of ``unicode`` and 'decode' is a method of ``str``, since you call 'decode', python "knows" how to convert from ``unicode`` to ``str`` and then call the 'decode' method, *that* conversion is made with the safe default "ascii" which raises an exception. + + +We need to know which one we are using **every time**. A possible way to avoid mistakes is to use ``leap_assert_type`` at the beginning of each method that has a ``str``/``unicode`` parameter. +The best approach we need to use ``unicode`` internally and when we read/write/transmit data, encode it to bytes (``str``). + + +Examples of problems found +-------------------------- + +* **logging data**: ``logger.debug("some string {0}".format(some_data))`` may fail if we have an ``unicode`` parameter because of the conversion needed to output it. + We need to use ``repr(some_data)`` to avoid encoding problems when sending data to the stdout. An easy way to do it is: ``logger.debug("some string {0!r}".format(some_data))`` + +- **paths encoding**: we should return always ``unicode`` values from helpers and encode them when we need to use it. + The stdlib handles correctly ``unicode`` strings path parameters. + If we want to do something else with the paths, we need to convert them manually using the system encoding. + +Regarding the encoding, use a hardcoded encoding may be wrong. +Instead of encode/decode using for instance 'utf-8', we should use this ``sys.getfilesystemencoding()`` + +For the data stored in a db (or something that is some way isolated from the system) we may want to choose 'utf-8' explicitly. + +Steps to improve code +--------------------- + +#. From now on, keep in mind the difference between ``str`` and ``unicode`` and write code consequently. +#. For each method we can add a ``leap_assert_type(parameter_name, unicode)`` (or ``str``) to avoid type problems. +#. Each time that is possible move towards the unicode 'frontier' (``unicode`` inside, ``str`` (bytes) outside). +#. When is possible update the methods parameters in order to be certain of the data types that we are handling. + +Recommended info +---------------- + +* PyCon 2012 talk: https://www.youtube.com/watch?v=sgHbC6udIqc + * article and transcription: http://nedbatchelder.com/text/unipain.html +* PyConAr 2012 (Spanish): http://www.youtube.com/watch?v=pQJ0emlYv50 +* Overcoming frustrations: http://pythonhosted.org/kitchen/unicode-frustrations.html +* Python's Unicode howto: http://docs.python.org/2/howto/unicode.html +* An encoding primer: http://www.danielmiessler.com/study/encoding/ diff --git a/docs/index.rst b/docs/index.rst index f210be8c..acf97ff3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -50,6 +50,7 @@ If you want to contribute to the project, we wrote this for you. dev/workflow dev/resources dev/internationalization + dev/encodings .. dev/internals dev/authors -- cgit v1.2.3 From fedc645fb3da90e58baba9c227697d83468f1dfb Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 4 Nov 2013 17:43:36 -0200 Subject: changelog formatting fix --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 09ea992e..38609a46 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,8 @@ History ------- 0.3.6 Nov 1 -- the "bạn có thể đọc này?" release: ++++++++++++++++++++++++++++++++++++++++++++++++++ + - Fix problem changing a non-ascii password. Closes #4003. - Enable password change in the client only if it has started the correct services. Closes #4093. -- cgit v1.2.3 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] --- changes/bug-4146_logger-window-html-support | 2 ++ src/leap/bitmask/gui/loggerwindow.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/bug-4146_logger-window-html-support diff --git a/changes/bug-4146_logger-window-html-support b/changes/bug-4146_logger-window-html-support new file mode 100644 index 00000000..27615d86 --- /dev/null +++ b/changes/bug-4146_logger-window-html-support @@ -0,0 +1,2 @@ +- Escape logs with html contents so they get displayed in plaintext + on the log viewer. Closes #4146. 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(-) 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] --- changes/bug-4358_handle-timeout-during-register | 1 + src/leap/bitmask/crypto/srpregister.py | 3 +-- src/leap/bitmask/gui/wizard.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 changes/bug-4358_handle-timeout-during-register diff --git a/changes/bug-4358_handle-timeout-during-register b/changes/bug-4358_handle-timeout-during-register new file mode 100644 index 00000000..04c408f6 --- /dev/null +++ b/changes/bug-4358_handle-timeout-during-register @@ -0,0 +1 @@ +- Handle Timeout errors during register process. Closes #4358. 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(-) 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 --- changes/bug_4379_osx_fixes | 1 + src/leap/bitmask/gui/mainwindow.py | 10 ++++------ src/leap/bitmask/gui/statemachines.py | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 changes/bug_4379_osx_fixes diff --git a/changes/bug_4379_osx_fixes b/changes/bug_4379_osx_fixes new file mode 100644 index 00000000..d2a83338 --- /dev/null +++ b/changes/bug_4379_osx_fixes @@ -0,0 +1 @@ +- Improve compatibility with OSX Mavericks. Fixes #4379. \ No newline at end of file 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] --- changes/bug-4148_wizard-ui-providers-back | 2 ++ src/leap/bitmask/gui/wizard.py | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 changes/bug-4148_wizard-ui-providers-back diff --git a/changes/bug-4148_wizard-ui-providers-back b/changes/bug-4148_wizard-ui-providers-back new file mode 100644 index 00000000..9c96400f --- /dev/null +++ b/changes/bug-4148_wizard-ui-providers-back @@ -0,0 +1,2 @@ +- Wizard now behaves correctly in provider selection after click 'cancel' or + 'back'. Closes #4148. 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 a4c7c3dbc37c00442fb8786b7cc0bf43daf54e4e Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Nov 2013 13:47:01 -0300 Subject: Support read-only remotes. --- pkg/scripts/bootstrap_develop.sh | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/scripts/bootstrap_develop.sh b/pkg/scripts/bootstrap_develop.sh index 4660c499..07063a81 100755 --- a/pkg/scripts/bootstrap_develop.sh +++ b/pkg/scripts/bootstrap_develop.sh @@ -38,12 +38,21 @@ clone_repos() { echo "${cc_green}Status: $status...${cc_normal}" set -x # show commands - # clone the leap.se repos - git clone ssh://gitolite@leap.se/bitmask_client - git clone ssh://gitolite@leap.se/leap_pycommon - git clone ssh://gitolite@leap.se/soledad - git clone ssh://gitolite@leap.se/keymanager - git clone ssh://gitolite@leap.se/leap_mail + if [[ "$1" == "ro" ]]; then + # read-only remotes: + git clone https://leap.se/git/bitmask_client + git clone https://leap.se/git/leap_pycommon + git clone https://leap.se/git/soledad + git clone https://leap.se/git/keymanager + git clone https://leap.se/git/leap_mail + else + # read-write remotes: + git clone ssh://gitolite@leap.se/bitmask_client + git clone ssh://gitolite@leap.se/leap_pycommon + git clone ssh://gitolite@leap.se/soledad + git clone ssh://gitolite@leap.se/keymanager + git clone ssh://gitolite@leap.se/leap_mail + fi set +x echo "${cc_green}Status: $status done!${cc_normal}" @@ -129,7 +138,7 @@ finish(){ } initialize() { - clone_repos + clone_repos $1 checkout_develop create_venv setup_develop @@ -169,6 +178,7 @@ help() { echo "Usage: $0 {init | update | help}" 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" @@ -177,7 +187,7 @@ help() { case "$1" in init) - initialize + initialize $2 ;; update) update -- 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] --- changes/feature-3958_add-hint-about-duration-of-key-generation | 1 + src/leap/bitmask/gui/mail_status.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changes/feature-3958_add-hint-about-duration-of-key-generation diff --git a/changes/feature-3958_add-hint-about-duration-of-key-generation b/changes/feature-3958_add-hint-about-duration-of-key-generation new file mode 100644 index 00000000..a5110e49 --- /dev/null +++ b/changes/feature-3958_add-hint-about-duration-of-key-generation @@ -0,0 +1 @@ +- Add hint to user about the duration of the key generation. Closes #3958. 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. --- changes/bug_4394_fix-mail-reinitialization | 1 + src/leap/bitmask/gui/mainwindow.py | 18 ++++++++------- src/leap/bitmask/services/mail/conductor.py | 35 ++++++++++++++++------------- 3 files changed, 31 insertions(+), 23 deletions(-) create mode 100644 changes/bug_4394_fix-mail-reinitialization diff --git a/changes/bug_4394_fix-mail-reinitialization b/changes/bug_4394_fix-mail-reinitialization new file mode 100644 index 00000000..f05fce6a --- /dev/null +++ b/changes/bug_4394_fix-mail-reinitialization @@ -0,0 +1 @@ +- Initialize mail service with the userid after login, to allow multiple accounts. Closes: #4394 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 dd0fb652aeef31719d888d40ed7d1268e8f2bd36 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 6 Nov 2013 17:12:15 -0200 Subject: add version_compat --- changes/VERSION_COMPAT | 1 + 1 file changed, 1 insertion(+) diff --git a/changes/VERSION_COMPAT b/changes/VERSION_COMPAT index cc00ecf7..e689170c 100644 --- a/changes/VERSION_COMPAT +++ b/changes/VERSION_COMPAT @@ -8,3 +8,4 @@ # # BEGIN DEPENDENCY LIST ------------------------- # leap.foo.bar>=x.y.z +leap.mail >= 0.3.7 -- 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(-) 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(-) 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 3237573421a5bfc2368878e324f030f0d7f3a3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 7 Nov 2013 07:40:58 -0300 Subject: Add changes file --- changes/bug_reject_bad_sender | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/bug_reject_bad_sender diff --git a/changes/bug_reject_bad_sender b/changes/bug_reject_bad_sender new file mode 100644 index 00000000..0a4f360f --- /dev/null +++ b/changes/bug_reject_bad_sender @@ -0,0 +1 @@ +- Give SMTP the current logged in userid. Related to #3952. \ No newline at end of file -- 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(-) 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 cf3e98eb1105bbf9a30878f886b276c366b190f3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 7 Nov 2013 10:51:05 -0300 Subject: Add changes file for #3814 and #3815. --- changes/bug-remember-checks-in-wizard | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/bug-remember-checks-in-wizard diff --git a/changes/bug-remember-checks-in-wizard b/changes/bug-remember-checks-in-wizard new file mode 100644 index 00000000..818926e7 --- /dev/null +++ b/changes/bug-remember-checks-in-wizard @@ -0,0 +1,2 @@ +- Remember provider checks in wizard, do not re-run them if the user goes back + and forth through the wizard. Closes #3814 and #3815. -- 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(-) 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(-) 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] --- ...ustom-systray-to-ease-tooltip-per-service-usage | 2 + 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 ++++++++++++++++++++++ 5 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage create mode 100644 src/leap/bitmask/gui/systray.py diff --git a/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage b/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage new file mode 100644 index 00000000..2eeb9594 --- /dev/null +++ b/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage @@ -0,0 +1,2 @@ +- Use custom SysTray in order to display per-service tooltip easily. + Closes #3998. 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(-) 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(-) 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(-) 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(-) 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 ae09f76bc63b434e08a9ffc59bf78f054f814bac Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 11 Nov 2013 14:40:41 -0300 Subject: Make all by default. --- docs/dev/quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/quickstart.rst b/docs/dev/quickstart.rst index 8ef7dfb8..96dcaeb9 100644 --- a/docs/dev/quickstart.rst +++ b/docs/dev/quickstart.rst @@ -61,7 +61,7 @@ also install the needed dependencies:: Compile the resource files:: - (bitmask)$ make resources + (bitmask)$ make Copy necessary files into system folders, with root privileges:: -- 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. --- changes/bug-4364_send-keys-whenever-keymanager-inits | 2 ++ src/leap/bitmask/services/soledad/soledadbootstrapper.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changes/bug-4364_send-keys-whenever-keymanager-inits diff --git a/changes/bug-4364_send-keys-whenever-keymanager-inits b/changes/bug-4364_send-keys-whenever-keymanager-inits new file mode 100644 index 00000000..0c3f6187 --- /dev/null +++ b/changes/bug-4364_send-keys-whenever-keymanager-inits @@ -0,0 +1,2 @@ + o Send user's key to nickserver whenever keymanager is initialized. Closes + #4364. 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 --- changes/changes_feature_4452_defer_initial_sync | 1 + src/leap/bitmask/services/soledad/soledadbootstrapper.py | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 changes/changes_feature_4452_defer_initial_sync diff --git a/changes/changes_feature_4452_defer_initial_sync b/changes/changes_feature_4452_defer_initial_sync new file mode 100644 index 00000000..44e1d2d2 --- /dev/null +++ b/changes/changes_feature_4452_defer_initial_sync @@ -0,0 +1 @@ +- Do not wait for initial soledad sync to complete to launch mail services. Closes: #4452 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(-) 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(-) 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 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 5140ddadb0b211d99cea7743d030d4c5de91f193 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 11:39:02 -0300 Subject: Add advanced key management ui to the makefile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1b4eed5d..00fec2ed 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ TRANSLAT_DIR = data/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 +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 RESOURCES = locale.qrc loggerwindow.qrc mainwindow.qrc icons.qrc -- 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(+) 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(-) 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] --- changes/bug-4449_password-change-properly-enabled | 1 + src/leap/bitmask/gui/mainwindow.py | 7 +++--- src/leap/bitmask/gui/preferenceswindow.py | 26 ++++++++++++----------- 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 changes/bug-4449_password-change-properly-enabled diff --git a/changes/bug-4449_password-change-properly-enabled b/changes/bug-4449_password-change-properly-enabled new file mode 100644 index 00000000..71d36eb2 --- /dev/null +++ b/changes/bug-4449_password-change-properly-enabled @@ -0,0 +1 @@ +- Password change dialog is now properly enabled. Closes #4449. 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(-) 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 From 07600853819d65959e9e2c9b96d62578442d3ae0 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 12:05:13 -0300 Subject: Add changelog for #4448 and VERSION_COMPAT --- changes/VERSION_COMPAT | 1 + changes/feature-4448_advanced-key-management | 1 + 2 files changed, 2 insertions(+) create mode 100644 changes/feature-4448_advanced-key-management diff --git a/changes/VERSION_COMPAT b/changes/VERSION_COMPAT index e689170c..71a3d477 100644 --- a/changes/VERSION_COMPAT +++ b/changes/VERSION_COMPAT @@ -9,3 +9,4 @@ # BEGIN DEPENDENCY LIST ------------------------- # leap.foo.bar>=x.y.z leap.mail >= 0.3.7 +leap.keymanager >= 0.3.6 diff --git a/changes/feature-4448_advanced-key-management b/changes/feature-4448_advanced-key-management new file mode 100644 index 00000000..85e77c39 --- /dev/null +++ b/changes/feature-4448_advanced-key-management @@ -0,0 +1 @@ +- Add advanced key management feature (Closes #4448). -- cgit v1.2.3 From 1b025459ee7f2ef287eb646eee0998698351adf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 15 Nov 2013 10:17:03 -0300 Subject: Update requirements --- changes/VERSION_COMPAT | 2 -- pkg/requirements.pip | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/changes/VERSION_COMPAT b/changes/VERSION_COMPAT index 71a3d477..cc00ecf7 100644 --- a/changes/VERSION_COMPAT +++ b/changes/VERSION_COMPAT @@ -8,5 +8,3 @@ # # BEGIN DEPENDENCY LIST ------------------------- # leap.foo.bar>=x.y.z -leap.mail >= 0.3.7 -leap.keymanager >= 0.3.6 diff --git a/pkg/requirements.pip b/pkg/requirements.pip index 885b19f8..04cd33de 100644 --- a/pkg/requirements.pip +++ b/pkg/requirements.pip @@ -20,8 +20,8 @@ zope.proxy leap.common>=0.3.4 leap.soledad.client>=0.4.2 -leap.keymanager>=0.3.4 -leap.mail>=0.3.6 +leap.keymanager>=0.3.6 +leap.mail>=0.3.7 # Remove this when u1db fixes its dependency on oauth oauth -- cgit v1.2.3 From 130969dec12ebd1b1c91a57508a83b3b770f5510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 15 Nov 2013 10:29:39 -0300 Subject: Fold in changes --- CHANGELOG.rst | 25 ++++++++++++++++++++++ ...ustom-systray-to-ease-tooltip-per-service-usage | 2 -- changes/bug-4146_logger-window-html-support | 2 -- changes/bug-4148_wizard-ui-providers-back | 2 -- changes/bug-4358_handle-timeout-during-register | 1 - .../bug-4364_send-keys-whenever-keymanager-inits | 2 -- changes/bug-4449_password-change-properly-enabled | 1 - changes/bug-remember-checks-in-wizard | 2 -- changes/bug_4379_osx_fixes | 1 - changes/bug_4394_fix-mail-reinitialization | 1 - changes/bug_reject_bad_sender | 1 - changes/changes_feature_4452_defer_initial_sync | 1 - ...-3958_add-hint-about-duration-of-key-generation | 1 - changes/feature-4448_advanced-key-management | 1 - changes/log_eip_status | 1 - 15 files changed, 25 insertions(+), 19 deletions(-) delete mode 100644 changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage delete mode 100644 changes/bug-4146_logger-window-html-support delete mode 100644 changes/bug-4148_wizard-ui-providers-back delete mode 100644 changes/bug-4358_handle-timeout-during-register delete mode 100644 changes/bug-4364_send-keys-whenever-keymanager-inits delete mode 100644 changes/bug-4449_password-change-properly-enabled delete mode 100644 changes/bug-remember-checks-in-wizard delete mode 100644 changes/bug_4379_osx_fixes delete mode 100644 changes/bug_4394_fix-mail-reinitialization delete mode 100644 changes/bug_reject_bad_sender delete mode 100644 changes/changes_feature_4452_defer_initial_sync delete mode 100644 changes/feature-3958_add-hint-about-duration-of-key-generation delete mode 100644 changes/feature-4448_advanced-key-management delete mode 100644 changes/log_eip_status diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 38609a46..4fc4246e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,31 @@ History ------- +0.3.7 Nov 15 -- the "The Big Lebowsky" release: ++++++++++++++++++++++++++++++++++++++++++++++++ +- Use custom SysTray in order to display per-service tooltip easily. + Closes #3998. +- Escape logs with html contents so they get displayed in plaintext + on the log viewer. Closes #4146. +- Wizard now behaves correctly in provider selection after click + 'cancel' or 'back'. Closes #4148. +- Handle Timeout errors during register process. Closes #4358. +- Send user's key to nickserver whenever keymanager is + initialized. Closes #4364. +- Password change dialog is now properly enabled. Closes #4449. +- Remember provider checks in wizard, do not re-run them if the user + goes back and forth through the wizard. Closes #3814 and #3815. +- Improve compatibility with OSX Mavericks. Fixes #4379. +- Initialize mail service with the userid after login, to allow + multiple accounts. Closes: #4394 +- Give SMTP the current logged in userid. Related to #3952. +- Do not wait for initial soledad sync to complete to launch mail + services. Closes: #4452 +- Add hint to user about the duration of the key generation. Closes + #3958. +- Add advanced key management feature. Closes #4448. +- Properly log EIP status changes. + 0.3.6 Nov 1 -- the "bạn có thể đọc này?" release: +++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage b/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage deleted file mode 100644 index 2eeb9594..00000000 --- a/changes/bug-3998_use-custom-systray-to-ease-tooltip-per-service-usage +++ /dev/null @@ -1,2 +0,0 @@ -- Use custom SysTray in order to display per-service tooltip easily. - Closes #3998. diff --git a/changes/bug-4146_logger-window-html-support b/changes/bug-4146_logger-window-html-support deleted file mode 100644 index 27615d86..00000000 --- a/changes/bug-4146_logger-window-html-support +++ /dev/null @@ -1,2 +0,0 @@ -- Escape logs with html contents so they get displayed in plaintext - on the log viewer. Closes #4146. diff --git a/changes/bug-4148_wizard-ui-providers-back b/changes/bug-4148_wizard-ui-providers-back deleted file mode 100644 index 9c96400f..00000000 --- a/changes/bug-4148_wizard-ui-providers-back +++ /dev/null @@ -1,2 +0,0 @@ -- Wizard now behaves correctly in provider selection after click 'cancel' or - 'back'. Closes #4148. diff --git a/changes/bug-4358_handle-timeout-during-register b/changes/bug-4358_handle-timeout-during-register deleted file mode 100644 index 04c408f6..00000000 --- a/changes/bug-4358_handle-timeout-during-register +++ /dev/null @@ -1 +0,0 @@ -- Handle Timeout errors during register process. Closes #4358. diff --git a/changes/bug-4364_send-keys-whenever-keymanager-inits b/changes/bug-4364_send-keys-whenever-keymanager-inits deleted file mode 100644 index 0c3f6187..00000000 --- a/changes/bug-4364_send-keys-whenever-keymanager-inits +++ /dev/null @@ -1,2 +0,0 @@ - o Send user's key to nickserver whenever keymanager is initialized. Closes - #4364. diff --git a/changes/bug-4449_password-change-properly-enabled b/changes/bug-4449_password-change-properly-enabled deleted file mode 100644 index 71d36eb2..00000000 --- a/changes/bug-4449_password-change-properly-enabled +++ /dev/null @@ -1 +0,0 @@ -- Password change dialog is now properly enabled. Closes #4449. diff --git a/changes/bug-remember-checks-in-wizard b/changes/bug-remember-checks-in-wizard deleted file mode 100644 index 818926e7..00000000 --- a/changes/bug-remember-checks-in-wizard +++ /dev/null @@ -1,2 +0,0 @@ -- Remember provider checks in wizard, do not re-run them if the user goes back - and forth through the wizard. Closes #3814 and #3815. diff --git a/changes/bug_4379_osx_fixes b/changes/bug_4379_osx_fixes deleted file mode 100644 index d2a83338..00000000 --- a/changes/bug_4379_osx_fixes +++ /dev/null @@ -1 +0,0 @@ -- Improve compatibility with OSX Mavericks. Fixes #4379. \ No newline at end of file diff --git a/changes/bug_4394_fix-mail-reinitialization b/changes/bug_4394_fix-mail-reinitialization deleted file mode 100644 index f05fce6a..00000000 --- a/changes/bug_4394_fix-mail-reinitialization +++ /dev/null @@ -1 +0,0 @@ -- Initialize mail service with the userid after login, to allow multiple accounts. Closes: #4394 diff --git a/changes/bug_reject_bad_sender b/changes/bug_reject_bad_sender deleted file mode 100644 index 0a4f360f..00000000 --- a/changes/bug_reject_bad_sender +++ /dev/null @@ -1 +0,0 @@ -- Give SMTP the current logged in userid. Related to #3952. \ No newline at end of file diff --git a/changes/changes_feature_4452_defer_initial_sync b/changes/changes_feature_4452_defer_initial_sync deleted file mode 100644 index 44e1d2d2..00000000 --- a/changes/changes_feature_4452_defer_initial_sync +++ /dev/null @@ -1 +0,0 @@ -- Do not wait for initial soledad sync to complete to launch mail services. Closes: #4452 diff --git a/changes/feature-3958_add-hint-about-duration-of-key-generation b/changes/feature-3958_add-hint-about-duration-of-key-generation deleted file mode 100644 index a5110e49..00000000 --- a/changes/feature-3958_add-hint-about-duration-of-key-generation +++ /dev/null @@ -1 +0,0 @@ -- Add hint to user about the duration of the key generation. Closes #3958. diff --git a/changes/feature-4448_advanced-key-management b/changes/feature-4448_advanced-key-management deleted file mode 100644 index 85e77c39..00000000 --- a/changes/feature-4448_advanced-key-management +++ /dev/null @@ -1 +0,0 @@ -- Add advanced key management feature (Closes #4448). diff --git a/changes/log_eip_status b/changes/log_eip_status deleted file mode 100644 index 32ac2b42..00000000 --- a/changes/log_eip_status +++ /dev/null @@ -1 +0,0 @@ -- Properly log EIP status changes. -- cgit v1.2.3 From 72f53cc32bf20b00bcbd5f28bab5fc25250215bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 15 Nov 2013 10:32:04 -0300 Subject: Update relnotes --- relnotes.txt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/relnotes.txt b/relnotes.txt index 2e32ca6c..99898aa2 100644 --- a/relnotes.txt +++ b/relnotes.txt @@ -1,8 +1,8 @@ -ANNOUNCING Bitmask, the internet encryption toolkit, release 0.3.5 +ANNOUNCING Bitmask, the internet encryption toolkit, release 0.3.7 The LEAP team is pleased to announce the immediate availability of -version 0.3.5 of Bitmask, the Internet Encryption Toolkit, codename -"I can stand on one foot". +version 0.3.7 of Bitmask, the Internet Encryption Toolkit, codename +"The Big Lebowsky". https://downloads.leap.se/client/ @@ -34,14 +34,9 @@ NOT trust your life to it (yet!). WHAT CAN THIS VERSION OF BITMASK DO FOR ME? -Bitmask 0.3.5 is a bugfix release but it also has improvements to the -UI design, it's still a work in progress since it will change after -testing in this release, but it's progressing nicely. We have again, -better mail support, with detached signatures and compliance with a -couple of RFC. You can refer to the CHANGELOG for the meat. - -We also re-added support for Windows, although it might be a bumpy -ride until we smooth the corners a little bit more. +Bitmask 0.3.7 improves greatly its mail support and stability in +general, among other various bug fixes. You can refer to the CHANGELOG +for the meat. As always, you can connect to the Encrypted Internet Proxy service offered by a provider of your choice, and enjoy a encrypted internet @@ -98,6 +93,6 @@ beyond any border. The LEAP team, -Oct 18, 2013 +Nov 15, 2013 Somewhere in the middle of the intertubes. EOF -- cgit v1.2.3