summaryrefslogtreecommitdiff
path: root/src/leap/keymanager/keys.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/keymanager/keys.py')
-rw-r--r--src/leap/keymanager/keys.py132
1 files changed, 104 insertions, 28 deletions
diff --git a/src/leap/keymanager/keys.py b/src/leap/keymanager/keys.py
index 91559c2..0de6a82 100644
--- a/src/leap/keymanager/keys.py
+++ b/src/leap/keymanager/keys.py
@@ -28,6 +28,7 @@ except ImportError:
import logging
import re
import time
+import traceback
from abc import ABCMeta, abstractmethod
@@ -110,39 +111,48 @@ def is_address(address):
return bool(re.match('[\w.-]+@[\w.-]+', address))
-def build_key_from_dict(kClass, kdict):
+def build_key_from_dict(kClass, key, active=None):
"""
Build an C{kClass} key based on info in C{kdict}.
- :param kdict: Dictionary with key data.
- :type kdict: dict
+ :param key: Dictionary with key data.
+ :type key: dict
+ :param active: Dictionary with active data.
+ :type active: dict
:return: An instance of the key.
:rtype: C{kClass}
"""
- try:
- validation = ValidationLevels.get(kdict[KEY_VALIDATION_KEY])
- except ValueError:
- logger.error("Not valid validation level (%s) for key %s",
- (kdict[KEY_VALIDATION_KEY], kdict[KEY_ID_KEY]))
- validation = ValidationLevels.Weak_Chain
-
- expiry_date = _to_datetime(kdict[KEY_EXPIRY_DATE_KEY])
- last_audited_at = _to_datetime(kdict[KEY_LAST_AUDITED_AT_KEY])
- refreshed_at = _to_datetime(kdict[KEY_REFRESHED_AT_KEY])
+ validation = ValidationLevels.Weak_Chain
+ last_audited_at = None
+ encr_used = False
+ sign_used = False
+
+ if active:
+ try:
+ validation = ValidationLevels.get(active[KEY_VALIDATION_KEY])
+ except ValueError:
+ logger.error("Not valid validation level (%s) for key %s",
+ (active[KEY_VALIDATION_KEY], active[KEY_ID_KEY]))
+ last_audited_at = _to_datetime(active[KEY_LAST_AUDITED_AT_KEY])
+ encr_used = active[KEY_ENCR_USED_KEY]
+ sign_used = active[KEY_SIGN_USED_KEY]
+
+ expiry_date = _to_datetime(key[KEY_EXPIRY_DATE_KEY])
+ refreshed_at = _to_datetime(key[KEY_REFRESHED_AT_KEY])
return kClass(
- kdict[KEY_ADDRESS_KEY],
- key_id=kdict[KEY_ID_KEY],
- fingerprint=kdict[KEY_FINGERPRINT_KEY],
- key_data=kdict[KEY_DATA_KEY],
- private=kdict[KEY_PRIVATE_KEY],
- length=kdict[KEY_LENGTH_KEY],
+ key[KEY_ADDRESS_KEY],
+ key_id=key[KEY_ID_KEY],
+ fingerprint=key[KEY_FINGERPRINT_KEY],
+ key_data=key[KEY_DATA_KEY],
+ private=key[KEY_PRIVATE_KEY],
+ length=key[KEY_LENGTH_KEY],
expiry_date=expiry_date,
last_audited_at=last_audited_at,
refreshed_at=refreshed_at,
validation=validation,
- encr_used=kdict[KEY_ENCR_USED_KEY],
- sign_used=kdict[KEY_SIGN_USED_KEY],
+ encr_used=encr_used,
+ sign_used=sign_used,
)
@@ -178,6 +188,7 @@ class EncryptionKey(object):
key_data="", private=False, length=0, expiry_date=None,
validation=ValidationLevels.Weak_Chain, last_audited_at=None,
refreshed_at=None, encr_used=False, sign_used=False):
+ # TODO: it should know its own active address
self.address = address
self.key_id = key_id
self.fingerprint = fingerprint
@@ -185,6 +196,7 @@ class EncryptionKey(object):
self.private = private
self.length = length
self.expiry_date = expiry_date
+
self.validation = validation
self.last_audited_at = last_audited_at
self.refreshed_at = refreshed_at
@@ -199,7 +211,6 @@ class EncryptionKey(object):
:rtype: str
"""
expiry_date = _to_unix_time(self.expiry_date)
- last_audited_at = _to_unix_time(self.last_audited_at)
refreshed_at = _to_unix_time(self.refreshed_at)
return json.dumps({
@@ -211,11 +222,7 @@ class EncryptionKey(object):
KEY_PRIVATE_KEY: self.private,
KEY_LENGTH_KEY: self.length,
KEY_EXPIRY_DATE_KEY: expiry_date,
- KEY_LAST_AUDITED_AT_KEY: last_audited_at,
KEY_REFRESHED_AT_KEY: refreshed_at,
- KEY_VALIDATION_KEY: str(self.validation),
- KEY_ENCR_USED_KEY: self.encr_used,
- KEY_SIGN_USED_KEY: self.sign_used,
KEY_TAGS_KEY: [KEYMANAGER_KEY_TAG],
})
@@ -223,16 +230,20 @@ class EncryptionKey(object):
"""
Return a JSON string describing this key.
- :param address: Address for wich the key is active
- :type address: str
:return: The JSON string describing this key.
:rtype: str
"""
+ last_audited_at = _to_unix_time(self.last_audited_at)
+
return json.dumps({
KEY_ADDRESS_KEY: address,
KEY_TYPE_KEY: self.__class__.__name__ + KEYMANAGER_ACTIVE_TYPE,
KEY_ID_KEY: self.key_id,
KEY_PRIVATE_KEY: self.private,
+ KEY_VALIDATION_KEY: str(self.validation),
+ KEY_LAST_AUDITED_AT_KEY: last_audited_at,
+ KEY_ENCR_USED_KEY: self.encr_used,
+ KEY_SIGN_USED_KEY: self.sign_used,
KEY_TAGS_KEY: [KEYMANAGER_ACTIVE_TAG],
})
@@ -464,3 +475,68 @@ class EncryptionScheme(object):
:rtype: bool
"""
pass
+
+ 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_ADDRESS_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_ID_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