summaryrefslogtreecommitdiff
path: root/keymanager/src/leap/keymanager/openpgp.py
diff options
context:
space:
mode:
Diffstat (limited to 'keymanager/src/leap/keymanager/openpgp.py')
-rw-r--r--keymanager/src/leap/keymanager/openpgp.py120
1 files changed, 116 insertions, 4 deletions
diff --git a/keymanager/src/leap/keymanager/openpgp.py b/keymanager/src/leap/keymanager/openpgp.py
index 82050cc..697ee8a 100644
--- a/keymanager/src/leap/keymanager/openpgp.py
+++ b/keymanager/src/leap/keymanager/openpgp.py
@@ -22,6 +22,7 @@ import os
import re
import shutil
import tempfile
+import traceback
import io
@@ -36,13 +37,19 @@ from leap.common.check import leap_assert, leap_assert_type, leap_check
from leap.keymanager import errors
from leap.keymanager.keys import (
EncryptionKey,
- EncryptionScheme,
+ init_indexes,
is_address,
build_key_from_dict,
TYPE_FINGERPRINT_PRIVATE_INDEX,
TYPE_ADDRESS_PRIVATE_INDEX,
KEY_UIDS_KEY,
KEY_FINGERPRINT_KEY,
+ KEY_REFRESHED_AT_KEY,
+ KEY_LAST_AUDITED_AT_KEY,
+ KEY_SIGN_USED_KEY,
+ KEY_ENCR_USED_KEY,
+ KEY_ADDRESS_KEY,
+ KEY_TYPE_KEY,
KEYMANAGER_ACTIVE_TYPE,
)
@@ -256,7 +263,7 @@ class OpenPGPKey(EncryptionKey):
self.refreshed_at = datetime.now()
-class OpenPGPScheme(EncryptionScheme):
+class OpenPGPScheme(object):
"""
A wrapper for OpenPGP keys management and use (encryption, decyption,
signing and verification).
@@ -275,9 +282,49 @@ class OpenPGPScheme(EncryptionScheme):
:param gpgbinary: Name for GnuPG binary executable.
:type gpgbinary: C{str}
"""
- EncryptionScheme.__init__(self, soledad)
- self._wait_indexes("get_key", "put_key")
+ self._soledad = soledad
self._gpgbinary = gpgbinary
+ self.deferred_init = init_indexes(soledad)
+ self.deferred_init.addCallback(self._migrate_documents_schema)
+ self._wait_indexes("get_key", "put_key")
+
+ def _migrate_documents_schema(self, _):
+ from leap.keymanager.migrator import KeyDocumentsMigrator
+ migrator = KeyDocumentsMigrator(self._soledad)
+ return migrator.migrate()
+
+ def _wait_indexes(self, *methods):
+ """
+ Methods that need to wait for the indexes to be ready.
+
+ Heavily based on
+ http://blogs.fluidinfo.com/terry/2009/05/11/a-mixin-class-allowing-python-__init__-methods-to-work-with-twisted-deferreds/
+
+ :param methods: methods that need to wait for the indexes to be ready
+ :type methods: tuple(str)
+ """
+ self.waiting = []
+ self.stored = {}
+
+ def restore(_):
+ for method in self.stored:
+ setattr(self, method, self.stored[method])
+ for d in self.waiting:
+ d.callback(None)
+
+ def makeWrapper(method):
+ def wrapper(*args, **kw):
+ d = defer.Deferred()
+ d.addCallback(lambda _: self.stored[method](*args, **kw))
+ self.waiting.append(d)
+ return d
+ return wrapper
+
+ for method in methods:
+ self.stored[method] = getattr(self, method)
+ setattr(self, method, makeWrapper(method))
+
+ self.deferred_init.addCallback(restore)
#
# Keys management
@@ -849,6 +896,71 @@ class OpenPGPScheme(EncryptionScheme):
return repair_func(doclist)
return doclist[0]
+ def _repair_key_docs(self, doclist):
+ """
+ If there is more than one key for a key id try to self-repair it
+
+ :return: a Deferred that will be fired with the valid key doc once all
+ the deletions are completed
+ :rtype: Deferred
+ """
+ def log_key_doc(doc):
+ logger.error("\t%s: %s" % (doc.content[KEY_UIDS_KEY],
+ doc.content[KEY_FINGERPRINT_KEY]))
+
+ def cmp_key(d1, d2):
+ return cmp(d1.content[KEY_REFRESHED_AT_KEY],
+ d2.content[KEY_REFRESHED_AT_KEY])
+
+ return self._repair_docs(doclist, cmp_key, log_key_doc)
+
+ def _repair_active_docs(self, doclist):
+ """
+ If there is more than one active doc for an address try to self-repair
+ it
+
+ :return: a Deferred that will be fired with the valid active doc once
+ all the deletions are completed
+ :rtype: Deferred
+ """
+ def log_active_doc(doc):
+ logger.error("\t%s: %s" % (doc.content[KEY_ADDRESS_KEY],
+ doc.content[KEY_FINGERPRINT_KEY]))
+
+ def cmp_active(d1, d2):
+ res = cmp(d1.content[KEY_LAST_AUDITED_AT_KEY],
+ d2.content[KEY_LAST_AUDITED_AT_KEY])
+ if res != 0:
+ return res
+
+ used1 = (d1.content[KEY_SIGN_USED_KEY] +
+ d1.content[KEY_ENCR_USED_KEY])
+ used2 = (d2.content[KEY_SIGN_USED_KEY] +
+ d2.content[KEY_ENCR_USED_KEY])
+ return cmp(used1, used2)
+
+ return self._repair_docs(doclist, cmp_active, log_active_doc)
+
+ def _repair_docs(self, doclist, cmp_func, log_func):
+ logger.error("BUG ---------------------------------------------------")
+ logger.error("There is more than one doc of type %s:"
+ % (doclist[0].content[KEY_TYPE_KEY],))
+
+ doclist.sort(cmp=cmp_func, reverse=True)
+ log_func(doclist[0])
+ deferreds = []
+ for doc in doclist[1:]:
+ log_func(doc)
+ d = self._soledad.delete_doc(doc)
+ deferreds.append(d)
+
+ logger.error("")
+ logger.error(traceback.extract_stack())
+ logger.error("BUG (please report above info) ------------------------")
+ d = defer.gatherResults(deferreds, consumeErrors=True)
+ d.addCallback(lambda _: doclist[0])
+ return d
+
def process_key(key_data, gpgbinary, secret=False):
with TempGPGWrapper(gpgbinary=gpgbinary) as gpg: