summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2013-08-26 14:19:11 +0200
committerKali Kaneko <kali@leap.se>2013-08-26 14:19:11 +0200
commitdbfaa0c69a3282ce221b4d30de2027ce9ee27a05 (patch)
tree46433f1326e85206db70edad78e3b6aa9122c04f
parent655a9a610cfe69530b8f6fde41e9255435374253 (diff)
parent6259826db4418be0bf05fee4785997575abe8177 (diff)
Merge branch 'master' into debian-0.3.1
-rw-r--r--CHANGELOG37
-rw-r--r--MANIFEST.in4
-rw-r--r--Makefile2
-rw-r--r--changes/bug-3425_replace-wizard-images1
-rw-r--r--changes/bug-update-requirements1
-rw-r--r--changes/bug3426_set_standalone1
-rw-r--r--changes/bug_3406_quit_hangs2
-rw-r--r--changes/bug_3413-soledad-init-retries1
-rw-r--r--changes/bug_better_hideshow_handling3
-rw-r--r--changes/bug_disablemail_completely2
-rw-r--r--changes/bug_handle_reconnecting1
-rw-r--r--changes/bug_improve_openvpn_detection3
-rw-r--r--changes/bug_load_kext2
-rw-r--r--changes/bug_properly_logout1
-rw-r--r--changes/bug_retr_hangs3
-rw-r--r--changes/bug_username_to_lower2
-rw-r--r--changes/feature-3407_add-log-filtering1
-rw-r--r--changes/feature_2959_create_bitmask_namespace1
-rw-r--r--changes/feature_3409-make-imap-poll-configurable2
-rw-r--r--changes/feature_3487-split-soledad-into-common-client-and-server2
-rw-r--r--changes/feature_3525-login-triggers-fetch1
-rw-r--r--changes/feature_add_mail_ui1
-rwxr-xr-xsetup.py4
-rw-r--r--src/leap/bitmask/crypto/srpauth.py82
-rw-r--r--src/leap/bitmask/gui/mainwindow.py19
-rw-r--r--src/leap/bitmask/gui/preferenceswindow.py196
-rw-r--r--src/leap/bitmask/gui/ui/mainwindow.ui11
-rw-r--r--src/leap/bitmask/gui/ui/preferences.ui170
-rw-r--r--versioneer.py73
29 files changed, 562 insertions, 67 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 8713b220..f8def7cb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,40 @@
+0.3.1 Aug 23:
+ o Replace wizard images with the rainbow mask. Closes #3425.
+ o Update leap.common minimum version needed.
+ o Set the standalone flag before it's being used. Fixes #3426.
+ o Stop the twisted reactor adding the stop call to the call chain
+ instead of stopping it directly. Fixes #3406.
+ o Allow soledad initialization to retry if it times out. Closes:
+ #3413
+ o Activate window when setting it visible. Also display Hide/Show
+ message in the tray icon taking into account the window
+ activation. Fixes #3433.
+ o Do not start IMAP daemon if mail was not selected among the
+ services. Fixes #3435.
+ o Reword RECONNECTING state of openvpn. Fixes #3429.
+ o Improve OpenVPN detection by searching for a specific leap-only
+ string in the command line. This makes it possible to run other
+ VPN instances while also using EIP. Fixes #3268 and #3364.
+ o OSX: Check for the tun.kext existence in /Library/Extensions
+ instead of /System/Library/Extensions. Fixes #3271.
+ o Use DELETE /1/logout to properly logout. Fixes #3510.
+ o Make the poll interval bigger to improve openvpn's internal
+ behavior. If it gets queried too many times per second, it's
+ behavior won't be good. Fixes #3430.
+ o Transforms usernames to lower case before they are used in the
+ registration and authentication. Closes #3541.
+ o Add filter option to the logger window. Closes #3407.
+ o Add a preference panel that lets you change your password. Closes
+ #3500 #2798 #3533.
+ o Move all client code into its own namespace
+ (leap.bitmask). Closes: #2959
+ o Make mail fetch interval in imap service configurable via
+ environment variable. Closes: #3409
+ o Update to new soledad package scheme (common, client and
+ server). Closes #3487.
+ o Fetch incoming mail when mail client logs in. Closes: #3525
+ o Add first draft of the UI for Encrypted Mail. Closes #3499.
+
0.3.0 Aug 9:
o Add missing scripts does not stop if a command fails, also warns
the user if there was an error. Closes #3294.
diff --git a/MANIFEST.in b/MANIFEST.in
index a4d18e0b..6334ce45 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,5 +4,5 @@ recursive-include docs api/* config/* dev/* man/* pkg/* testers/* user/*
prune docs/_build
prune docs/covhtml
include versioneer.py
-include src/leap/util/reqs.txt
-include src/leap/crypto/tests/wrongcert.pem
+include src/leap/bitmask/util/reqs.txt
+include src/leap/bitmask/crypto/tests/wrongcert.pem
diff --git a/Makefile b/Makefile
index f58abbd9..69cf29ed 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ TRANSLAT_DIR = data/translations
PROJFILE = data/bitmask.pro
#UI files to compile
-UI_FILES = loggerwindow.ui mainwindow.ui wizard.ui login.ui statuspanel.ui
+UI_FILES = loggerwindow.ui mainwindow.ui wizard.ui login.ui statuspanel.ui preferences.ui
#Qt resource files to compile
RESOURCES = locale.qrc loggerwindow.qrc mainwindow.qrc icons.qrc
diff --git a/changes/bug-3425_replace-wizard-images b/changes/bug-3425_replace-wizard-images
deleted file mode 100644
index cf5cbd9d..00000000
--- a/changes/bug-3425_replace-wizard-images
+++ /dev/null
@@ -1 +0,0 @@
- o Replace wizard images with the rainbow mask. Closes #3425.
diff --git a/changes/bug-update-requirements b/changes/bug-update-requirements
deleted file mode 100644
index e86e6e84..00000000
--- a/changes/bug-update-requirements
+++ /dev/null
@@ -1 +0,0 @@
- o Update leap.common minimum version needed.
diff --git a/changes/bug3426_set_standalone b/changes/bug3426_set_standalone
deleted file mode 100644
index 408b893f..00000000
--- a/changes/bug3426_set_standalone
+++ /dev/null
@@ -1 +0,0 @@
- o Set the standalone flag before it's being used. Fixes #3426. \ No newline at end of file
diff --git a/changes/bug_3406_quit_hangs b/changes/bug_3406_quit_hangs
deleted file mode 100644
index 77452780..00000000
--- a/changes/bug_3406_quit_hangs
+++ /dev/null
@@ -1,2 +0,0 @@
- o Stop the twisted reactor adding the stop call to the call chain
- instead of stopping it directly. Fixes #3406. \ No newline at end of file
diff --git a/changes/bug_3413-soledad-init-retries b/changes/bug_3413-soledad-init-retries
deleted file mode 100644
index 160121dd..00000000
--- a/changes/bug_3413-soledad-init-retries
+++ /dev/null
@@ -1 +0,0 @@
- o Allow soledad initialization to retry if it times out. Closes: #3413
diff --git a/changes/bug_better_hideshow_handling b/changes/bug_better_hideshow_handling
deleted file mode 100644
index 3538087b..00000000
--- a/changes/bug_better_hideshow_handling
+++ /dev/null
@@ -1,3 +0,0 @@
- o Activate window when setting it visible. Also display Hide/Show
- message in the tray icon taking into account the window
- activation. Fixes #3433. \ No newline at end of file
diff --git a/changes/bug_disablemail_completely b/changes/bug_disablemail_completely
deleted file mode 100644
index 126da2a7..00000000
--- a/changes/bug_disablemail_completely
+++ /dev/null
@@ -1,2 +0,0 @@
- o Do not start IMAP daemon if mail was not selected among the
- services. Fixes #3435. \ No newline at end of file
diff --git a/changes/bug_handle_reconnecting b/changes/bug_handle_reconnecting
deleted file mode 100644
index c6465949..00000000
--- a/changes/bug_handle_reconnecting
+++ /dev/null
@@ -1 +0,0 @@
- o Reword RECONNECTING state of openvpn. Fixes #3429. \ No newline at end of file
diff --git a/changes/bug_improve_openvpn_detection b/changes/bug_improve_openvpn_detection
deleted file mode 100644
index 99f43a07..00000000
--- a/changes/bug_improve_openvpn_detection
+++ /dev/null
@@ -1,3 +0,0 @@
- o Improve OpenVPN detection by searching for a specific leap-only
- string in the command line. This makes it possible to run other
- VPN instances while also using EIP. Fixes #3268 and #3364. \ No newline at end of file
diff --git a/changes/bug_load_kext b/changes/bug_load_kext
deleted file mode 100644
index ba4a44cf..00000000
--- a/changes/bug_load_kext
+++ /dev/null
@@ -1,2 +0,0 @@
- o OSX: Check for the tun.kext existence in /Library/Extensions
- instead of /System/Library/Extensions. Fixes #3271. \ No newline at end of file
diff --git a/changes/bug_properly_logout b/changes/bug_properly_logout
deleted file mode 100644
index a5d0d972..00000000
--- a/changes/bug_properly_logout
+++ /dev/null
@@ -1 +0,0 @@
- o Use DELETE /1/logout to properly logout. Fixes #3510. \ No newline at end of file
diff --git a/changes/bug_retr_hangs b/changes/bug_retr_hangs
deleted file mode 100644
index 8bdf7bac..00000000
--- a/changes/bug_retr_hangs
+++ /dev/null
@@ -1,3 +0,0 @@
- o Make the poll interval bigger to improve openvpn's internal
- behavior. If it gets queried too many times per second, it's
- behavior won't be good. Fixes #3430. \ No newline at end of file
diff --git a/changes/bug_username_to_lower b/changes/bug_username_to_lower
deleted file mode 100644
index 284567e4..00000000
--- a/changes/bug_username_to_lower
+++ /dev/null
@@ -1,2 +0,0 @@
- o Transforms usernames to lower case before they are used in the
- registration and authentication. Closes #3541. \ No newline at end of file
diff --git a/changes/feature-3407_add-log-filtering b/changes/feature-3407_add-log-filtering
deleted file mode 100644
index f4433af4..00000000
--- a/changes/feature-3407_add-log-filtering
+++ /dev/null
@@ -1 +0,0 @@
- o Add filter option to the logger window. Closes #3407.
diff --git a/changes/feature_2959_create_bitmask_namespace b/changes/feature_2959_create_bitmask_namespace
deleted file mode 100644
index 9f7e9cd4..00000000
--- a/changes/feature_2959_create_bitmask_namespace
+++ /dev/null
@@ -1 +0,0 @@
- o Move all client code into its own namespace (leap.bitmask). Closes: #2959
diff --git a/changes/feature_3409-make-imap-poll-configurable b/changes/feature_3409-make-imap-poll-configurable
deleted file mode 100644
index 8730b5ab..00000000
--- a/changes/feature_3409-make-imap-poll-configurable
+++ /dev/null
@@ -1,2 +0,0 @@
- o Make mail fetch interval in imap service configurable via environment
- variable. Closes: #3409
diff --git a/changes/feature_3487-split-soledad-into-common-client-and-server b/changes/feature_3487-split-soledad-into-common-client-and-server
deleted file mode 100644
index 46983232..00000000
--- a/changes/feature_3487-split-soledad-into-common-client-and-server
+++ /dev/null
@@ -1,2 +0,0 @@
- o Update to new soledad package scheme (common, client and server). Closes
- #3487.
diff --git a/changes/feature_3525-login-triggers-fetch b/changes/feature_3525-login-triggers-fetch
deleted file mode 100644
index 02fd0978..00000000
--- a/changes/feature_3525-login-triggers-fetch
+++ /dev/null
@@ -1 +0,0 @@
- o Fetch incoming mail when mail client logs in. Closes: #3525
diff --git a/changes/feature_add_mail_ui b/changes/feature_add_mail_ui
deleted file mode 100644
index c7c0f2ce..00000000
--- a/changes/feature_add_mail_ui
+++ /dev/null
@@ -1 +0,0 @@
- o Add first draft of the UI for Encrypted Mail. Closes #3499. \ No newline at end of file
diff --git a/setup.py b/setup.py
index 09d0661c..2c80eb5c 100755
--- a/setup.py
+++ b/setup.py
@@ -52,14 +52,14 @@ trove_classifiers = [
parsed_reqs = utils.parse_requirements()
cmdclass = versioneer.get_cmdclass()
-leap_launcher = 'bitmask=leap.app:main'
+leap_launcher = 'bitmask=leap.bitmask.app:main'
from setuptools.command.develop import develop as _develop
def copy_reqs(path, withsrc=False):
# add a copy of the processed requirements to the package
- _reqpath = ('leap', 'util', 'reqs.txt')
+ _reqpath = ('leap', 'bitmask', 'util', 'reqs.txt')
if withsrc:
reqsfile = os.path.join(path, 'src', *_reqpath)
else:
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 7b91205f..41ce130a 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -134,6 +134,8 @@ class SRPAuth(QtCore.QObject):
A_KEY = "A"
CLIENT_AUTH_KEY = "client_auth"
SESSION_ID_KEY = "_session_id"
+ USER_VERIFIER_KEY = 'user[password_verifier]'
+ USER_SALT_KEY = 'user[password_salt]'
def __init__(self, provider_config):
"""
@@ -169,6 +171,10 @@ class SRPAuth(QtCore.QObject):
self._srp_user = None
self._srp_a = None
+ # User credentials stored for password changing checks
+ self._username = None
+ self._password = None
+
def _safe_unhexlify(self, val):
"""
Rounds the val to a multiple of 2 and returns the
@@ -438,6 +444,51 @@ class SRPAuth(QtCore.QObject):
def _threader(self, cb, res, *args, **kwargs):
return threads.deferToThread(cb, res, *args, **kwargs)
+ def change_password(self, current_password, new_password):
+ """
+ Changes the password for the currently logged user if the current
+ password match.
+ It requires to be authenticated.
+
+ Might raise:
+ SRPAuthBadPassword
+ requests.exceptions.HTTPError
+
+ :param current_password: the current password for the logged user.
+ :type current_password: str
+ :param new_password: the new password for the user
+ :type new_password: str
+ """
+ leap_assert(self.get_uid() is not None)
+
+ if current_password != self._password:
+ raise SRPAuthBadPassword
+
+ url = "%s/%s/users/%s.json" % (
+ self._provider_config.get_api_uri(),
+ self._provider_config.get_api_version(),
+ self.get_uid())
+
+ salt, verifier = self._srp.create_salted_verification_key(
+ self._username, new_password, self._hashfun, self._ng)
+
+ cookies = {self.SESSION_ID_KEY: self.get_session_id()}
+ user_data = {
+ self.USER_VERIFIER_KEY: binascii.hexlify(verifier),
+ self.USER_SALT_KEY: binascii.hexlify(salt)
+ }
+
+ change_password = self._session.put(
+ url, data=user_data,
+ verify=self._provider_config.get_ca_cert_path(),
+ cookies=cookies,
+ timeout=REQUEST_TIMEOUT)
+
+ # In case of non 2xx it raises HTTPError
+ change_password.raise_for_status()
+
+ self._password = new_password
+
def authenticate(self, username, password):
"""
Executes the whole authentication process for a user
@@ -454,6 +505,10 @@ class SRPAuth(QtCore.QObject):
"""
leap_assert(self.get_session_id() is None, "Already logged in")
+ # User credentials stored for password changing checks
+ self._username = username.lower()
+ self._password = password
+
d = threads.deferToThread(self._authentication_preprocessing,
username=username,
password=password)
@@ -565,6 +620,33 @@ class SRPAuth(QtCore.QObject):
d.addErrback(self._errback)
return d
+ def change_password(self, current_password, new_password):
+ """
+ Changes the user's password.
+
+ :param current_password: the current password of the user.
+ :type current_password: str
+ :param new_password: the new password for the user.
+ :type new_password: str
+
+ :returns: a defer to interact with.
+ :rtype: twisted.internet.defer.Deferred
+ """
+ d = threads.deferToThread(
+ self.__instance.change_password, current_password, new_password)
+ return d
+
+ def get_username(self):
+ """
+ Returns the username of the currently authenticated user or None if
+ no user is logged.
+
+ :rtype: str or None
+ """
+ if self.get_uid() is None:
+ return None
+ return self.__instance._username
+
def _gui_notify(self, _):
"""
Callback that notifies the UI with the proper signal.
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 17275983..c832887a 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -33,6 +33,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.preferenceswindow import PreferencesWindow
from leap.bitmask.gui.wizard import Wizard
from leap.bitmask.gui.login import LoginWidget
from leap.bitmask.gui.statuspanel import StatusPanelWidget
@@ -162,6 +163,7 @@ class MainWindow(QtGui.QMainWindow):
self._launch_wizard)
self.ui.btnShowLog.clicked.connect(self._show_logger_window)
+ self.ui.btnPreferences.clicked.connect(self._show_preferences)
self._status_panel = StatusPanelWidget(
self.ui.stackedWidget.widget(self.EIP_STATUS_INDEX))
@@ -286,12 +288,17 @@ class MainWindow(QtGui.QMainWindow):
################################# end Qt Signals connection ########
+ # Enable the password change when soledad is ready
+ self.soledad_ready.connect(
+ partial(self.ui.btnPreferences.setEnabled, True))
+
init_platform()
self._wizard = None
self._wizard_firstrun = False
self._logger_window = None
+ self._preferences_window = None
self._bypass_checks = bypass_checks
@@ -403,6 +410,17 @@ class MainWindow(QtGui.QMainWindow):
self._logger_window.finished.connect(self._uncheck_logger_button)
+ def _show_preferences(self):
+ """
+ SLOT
+ TRIGGERS:
+ self.ui.action_show_preferences.triggered
+ self.ui.btnPreferences.clicked
+
+ Displays the preferences window.
+ """
+ PreferencesWindow(self, self._srp_auth, self._soledad).show()
+
def _uncheck_logger_button(self):
"""
SLOT
@@ -1399,6 +1417,7 @@ class MainWindow(QtGui.QMainWindow):
self._login_widget.set_password("")
self._login_widget.set_enabled(True)
self._login_widget.set_status("")
+ self.ui.btnPreferences.setEnabled(False)
def _intermediate_stage(self, data):
"""
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
new file mode 100644
index 00000000..67448768
--- /dev/null
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -0,0 +1,196 @@
+# -*- coding: utf-8 -*-
+# preferenceswindow.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 <http://www.gnu.org/licenses/>.
+
+"""
+Preferences window
+"""
+import logging
+
+from functools import partial
+from PySide import QtGui
+
+from leap.bitmask.gui.ui_preferences import Ui_Preferences
+from leap.soledad.client import NoStorageSecret
+from leap.bitmask.crypto.srpauth import SRPAuthBadPassword
+
+logger = logging.getLogger(__name__)
+
+
+class PreferencesWindow(QtGui.QDialog):
+ """
+ Window that displays the preferences.
+ """
+
+ WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password")
+
+ def __init__(self, parent, srp_auth, soledad):
+ """
+ :param parent: parent object of the PreferencesWindow.
+ :parent type: QWidget
+ :param srp_auth: SRPAuth object configured in the main app.
+ :type srp_auth: SRPAuth
+ :param soledad: Soledad object configured in the main app.
+ :type soledad: Soledad
+ """
+ QtGui.QDialog.__init__(self, parent)
+
+ self._srp_auth = srp_auth
+ self._soledad = soledad
+
+ # Load UI
+ self.ui = Ui_Preferences()
+ self.ui.setupUi(self)
+ self.ui.lblPasswordChangeStatus.setVisible(False)
+
+ # Connections
+ self.ui.pbChangePassword.clicked.connect(self._change_password)
+
+ def _basic_password_checks(self, username, password, password2):
+ """
+ Performs basic password checks to avoid really easy passwords.
+
+ :param username: username provided at the registrarion form
+ :type username: str
+ :param password: password from the registration form
+ :type password: str
+ :param password2: second password from the registration form
+ :type password: str
+
+ :returns: True and empty message if all the checks pass,
+ False and an error message otherwise
+ :rtype: tuple(bool, str)
+ """
+ message = None
+
+ if message is None and password != password2:
+ message = self.tr("Passwords don't match")
+
+ if message is None and len(password) < 6:
+ message = self.tr("Password too short")
+
+ if message is None and password in self.WEAK_PASSWORDS:
+ message = self.tr("Password too easy")
+
+ if message is None and username == password:
+ message = self.tr("Password equal to username")
+
+ return message is None, message
+
+ def _set_password_change_status(self, status, error=False, success=False):
+ """
+ Sets the status label for the password change.
+
+ :param status: status message to display, can be HTML
+ :type status: str
+ """
+ if error:
+ status = "<font color='red'><b>%s</b></font>" % (status,)
+ elif success:
+ status = "<font color='green'><b>%s</b></font>" % (status,)
+
+ self.ui.lblPasswordChangeStatus.setVisible(True)
+ self.ui.lblPasswordChangeStatus.setText(status)
+
+ def _set_changing_password(self, disable):
+ """
+ Enables or disables the widgets in the password change group box.
+
+ :param disable: True if the widgets should be disabled and
+ it displays the status label that shows that is
+ changing the password.
+ False if they should be enabled.
+ :type disable: bool
+ """
+ if disable:
+ self._set_password_change_disable(self.tr("Changing password..."))
+
+ self.ui.leCurrentPassword.setEnabled(not disable)
+ self.ui.leNewPassword.setEnabled(not disable)
+ self.ui.leNewPassword2.setEnabled(not disable)
+ self.ui.pbChangePassword.setEnabled(not disable)
+
+ def _change_password(self):
+ """
+ Changes the user's password if the inputboxes are correctly filled.
+ """
+ username = self._srp_auth.get_username()
+ current_password = self.ui.leCurrentPassword.text()
+ new_password = self.ui.leNewPassword.text()
+ new_password2 = self.ui.leNewPassword2.text()
+
+ ok, msg = self._basic_password_checks(
+ username, new_password, new_password2)
+
+ if not ok:
+ self._set_changing_password(False)
+ self._set_password_change_status(msg, error=True)
+ self.ui.leNewPassword.setFocus()
+ return
+
+ self._set_changing_password(True)
+ d = self._srp_auth.change_password(current_password, new_password)
+ d.addCallback(partial(self._change_password_success, new_password))
+ d.addErrback(self._change_password_problem)
+
+ def _change_password_success(self, new_password, _):
+ """
+ Callback used to display a successfully performed action.
+
+ :param new_password: the new password for the user.
+ :type new_password: str.
+ :param _: the returned data from self._srp_auth.change_password
+ Ignored
+ """
+ logger.debug("SRP password changed successfully.")
+ try:
+ self._soledad.change_passphrase(str(new_password))
+ logger.debug("Soledad password changed successfully.")
+ except NoStorageSecret:
+ logger.debug(
+ "No storage secret for password change in Soledad.")
+
+ self._set_password_change_status(
+ self.tr("Password changed successfully."), success=True)
+ self._clear_inputs()
+ self._set_changing_password(False)
+
+ def _change_password_problem(self, failure):
+ """
+ Errback called if there was a problem with the deferred.
+ Also is used to display an error message.
+
+ :param failure: the cause of the method failed.
+ :type failure: twisted.python.Failure
+ """
+ logger.error("Error changing password: %s", (failure, ))
+ problem = self.tr("There was a problem changing the password.")
+
+ if failure.check(SRPAuthBadPassword):
+ problem = self.tr("You did not enter a correct current password.")
+
+ self._set_password_change_status(problem, error=True)
+
+ self._set_changing_password(False)
+ failure.trap(Exception)
+
+ def _clear_inputs(self):
+ """
+ Clear the contents of the inputs.
+ """
+ self.ui.leCurrentPassword.setText("")
+ self.ui.leNewPassword.setText("")
+ self.ui.leNewPassword2.setText("")
diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui
index 9c4e6ff0..834a562e 100644
--- a/src/leap/bitmask/gui/ui/mainwindow.ui
+++ b/src/leap/bitmask/gui/ui/mainwindow.ui
@@ -215,6 +215,16 @@
<item row="18" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
+ <widget class="QPushButton" name="btnPreferences">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Preferences</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -310,7 +320,6 @@
<resources>
<include location="../../../../../data/resources/mainwindow.qrc"/>
<include location="../../../../../data/resources/locale.qrc"/>
- <include location="../../../../data/resources/mainwindow.qrc"/>
</resources>
<connections/>
</ui>
diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui
new file mode 100644
index 00000000..8c63ccad
--- /dev/null
+++ b/src/leap/bitmask/gui/ui/preferences.ui
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Preferences</class>
+ <widget class="QDialog" name="Preferences">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>451</width>
+ <height>267</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="gbPasswordChange">
+ <property name="title">
+ <string>Password Change</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblCurrentPassword">
+ <property name="text">
+ <string>&amp;Current password:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leCurrentPassword</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="leCurrentPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblNewPassword">
+ <property name="text">
+ <string>&amp;New password:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leNewPassword</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="leNewPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lblNewPassword2">
+ <property name="text">
+ <string>&amp;Re-enter new password:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leNewPassword2</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="leNewPassword2">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QPushButton" name="pbChangePassword">
+ <property name="text">
+ <string>Change</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="lblPasswordChangeStatus">
+ <property name="text">
+ <string>&lt;Password change status&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="gbGatewaySelector">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="title">
+ <string>Select gateway for provider</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblSelectProvider">
+ <property name="text">
+ <string>&amp;Select provider:</string>
+ </property>
+ <property name="buddy">
+ <cstring>cbProviders</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="cbProviders">
+ <item>
+ <property name="text">
+ <string>&lt;Select provider&gt;</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Select gateway:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="comboBox">
+ <item>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/versioneer.py b/versioneer.py
index 57d99419..34e48073 100644
--- a/versioneer.py
+++ b/versioneer.py
@@ -74,8 +74,8 @@ To use it:
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
4: run 'setup.py update_files', which will create _version.py, and will
- append the following to your __init__.py:
- from _version import __version__
+ modify your __init__.py to define __version__ (by calling a function
+ from _version.py)
5: modify your MANIFEST.in to include versioneer.py
6: add both versioneer.py and the generated _version.py to your VCS
"""
@@ -144,7 +144,8 @@ def get_expanded_variables(versionfile_source):
# used from _version.py.
variables = {}
try:
- for line in open(versionfile_source,"r").readlines():
+ f = open(versionfile_source,"r")
+ for line in f.readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
@@ -153,6 +154,7 @@ def get_expanded_variables(versionfile_source):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
variables["full"] = mo.group(1)
+ f.close()
except EnvironmentError:
pass
return variables
@@ -164,20 +166,24 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
print("variables are unexpanded, not using")
return {} # unexpanded, so not in an unpacked git-archive tarball
refs = set([r.strip() for r in refnames.strip("()").split(",")])
- for ref in list(refs):
- if not re.search(r'\d', ref):
- if verbose:
- print("discarding '%%s', no digits" %% ref)
- refs.discard(ref)
- # Assume all version tags have a digit. git's %%d expansion
- # behaves like git log --decorate=short and strips out the
- # refs/heads/ and refs/tags/ prefixes that would let us
- # distinguish between branches and tags. By ignoring refnames
- # without digits, we filter out many common branch names like
- # "release" and "stabilization", as well as "HEAD" and "master".
+ # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
+ # just "foo-1.0". If we see a "tag: " prefix, prefer those.
+ TAG = "tag: "
+ tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+ if not tags:
+ # Either we're using git < 1.8.3, or there really are no tags. We use
+ # a heuristic: assume all version tags have a digit. The old git %%d
+ # expansion behaves like git log --decorate=short and strips out the
+ # refs/heads/ and refs/tags/ prefixes that would let us distinguish
+ # between branches and tags. By ignoring refnames without digits, we
+ # filter out many common branch names like "release" and
+ # "stabilization", as well as "HEAD" and "master".
+ tags = set([r for r in refs if re.search(r'\d', r)])
+ if verbose:
+ print("discarding '%%s', no digits" %% ",".join(refs-tags))
if verbose:
- print("remaining refs: %%s" %% ",".join(sorted(refs)))
- for ref in sorted(refs):
+ print("likely tags: %%s" %% ",".join(sorted(tags)))
+ for ref in sorted(tags):
# sorting will prefer e.g. "2.0" over "2.0rc1"
if ref.startswith(tag_prefix):
r = ref[len(tag_prefix):]
@@ -328,7 +334,8 @@ def get_expanded_variables(versionfile_source):
# used from _version.py.
variables = {}
try:
- for line in open(versionfile_source,"r").readlines():
+ f = open(versionfile_source,"r")
+ for line in f.readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
@@ -337,6 +344,7 @@ def get_expanded_variables(versionfile_source):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
variables["full"] = mo.group(1)
+ f.close()
except EnvironmentError:
pass
return variables
@@ -348,20 +356,24 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
print("variables are unexpanded, not using")
return {} # unexpanded, so not in an unpacked git-archive tarball
refs = set([r.strip() for r in refnames.strip("()").split(",")])
- for ref in list(refs):
- if not re.search(r'\d', ref):
- if verbose:
- print("discarding '%s', no digits" % ref)
- refs.discard(ref)
- # Assume all version tags have a digit. git's %d expansion
- # behaves like git log --decorate=short and strips out the
- # refs/heads/ and refs/tags/ prefixes that would let us
- # distinguish between branches and tags. By ignoring refnames
- # without digits, we filter out many common branch names like
- # "release" and "stabilization", as well as "HEAD" and "master".
+ # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
+ # just "foo-1.0". If we see a "tag: " prefix, prefer those.
+ TAG = "tag: "
+ tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
+ if not tags:
+ # Either we're using git < 1.8.3, or there really are no tags. We use
+ # a heuristic: assume all version tags have a digit. The old git %d
+ # expansion behaves like git log --decorate=short and strips out the
+ # refs/heads/ and refs/tags/ prefixes that would let us distinguish
+ # between branches and tags. By ignoring refnames without digits, we
+ # filter out many common branch names like "release" and
+ # "stabilization", as well as "HEAD" and "master".
+ tags = set([r for r in refs if re.search(r'\d', r)])
+ if verbose:
+ print("discarding '%s', no digits" % ",".join(refs-tags))
if verbose:
- print("remaining refs: %s" % ",".join(sorted(refs)))
- for ref in sorted(refs):
+ print("likely tags: %s" % ",".join(sorted(tags)))
+ for ref in sorted(tags):
# sorting will prefer e.g. "2.0" over "2.0rc1"
if ref.startswith(tag_prefix):
r = ref[len(tag_prefix):]
@@ -513,6 +525,7 @@ def versions_from_file(filename):
mo = re.match("version_full = '([^']+)'", line)
if mo:
versions["full"] = mo.group(1)
+ f.close()
return versions
def write_to_version_file(filename, versions):