summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--changes/VERSION_COMPAT1
-rw-r--r--changes/feature-4448_advanced-key-management1
-rw-r--r--src/leap/bitmask/gui/advanced_key_management.py185
-rw-r--r--src/leap/bitmask/gui/mainwindow.py19
-rw-r--r--src/leap/bitmask/gui/ui/advanced_key_management.ui153
-rw-r--r--src/leap/bitmask/gui/ui/mainwindow.ui13
7 files changed, 371 insertions, 3 deletions
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
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).
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 <http://www.gnu.org/licenses/>.
+"""
+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("<span style='color:#0000FF;'>NOTE</span>: "
+ "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(
+ "<span style='color:#ff0000;'>WARNING</span>:<br>"
+ "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/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index c24735d8..b0f25af1 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
@@ -1521,6 +1539,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/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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AdvancedKeyManagement</class>
+ <widget class="QWidget" name="AdvancedKeyManagement">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>431</width>
+ <height>188</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Advanced Key Management</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="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QWidget" name="container" native="true">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="leUser">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>user_name@provider</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Key ID:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="leKeyID">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>key ID</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Key fingerprint:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="leFingerprint">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>fingerprint</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <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>
+ <item row="4" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="1">
+ <widget class="QPushButton" name="pbExportKeys">
+ <property name="text">
+ <string>Export current key pair</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" rowspan="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <widget class="QPushButton" name="pbImportKeys">
+ <property name="text">
+ <string>Import custom key pair</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblStatus">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ </resources>
+ <connections/>
+</ui>
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 @@
<x>0</x>
<y>0</y>
<width>524</width>
- <height>636</height>
+ <height>651</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -380,7 +380,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb
<x>0</x>
<y>0</y>
<width>524</width>
- <height>22</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -388,6 +388,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb
<string>&amp;Bitmask</string>
</property>
<addaction name="action_create_new_account"/>
+ <addaction name="action_advanced_key_management"/>
<addaction name="separator"/>
<addaction name="action_quit"/>
</widget>
@@ -439,6 +440,14 @@ background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgb
<string>Create a new account...</string>
</property>
</action>
+ <action name="action_advanced_key_management">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Advanced Key Management</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="../../../../../data/resources/mainwindow.qrc"/>