diff options
| -rw-r--r-- | keymanager/src/leap/keymanager/__init__.py | 7 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/documents.py | 101 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/keys.py | 163 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/migrator.py | 70 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/openpgp.py | 4 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/tests/test_migrator.py | 2 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/tests/test_openpgp.py | 6 | 
7 files changed, 174 insertions, 179 deletions
| diff --git a/keymanager/src/leap/keymanager/__init__.py b/keymanager/src/leap/keymanager/__init__.py index 32e5581..6420f9a 100644 --- a/keymanager/src/leap/keymanager/__init__.py +++ b/keymanager/src/leap/keymanager/__init__.py @@ -76,11 +76,8 @@ from leap.keymanager.errors import (  )  from leap.keymanager.validation import ValidationLevels, can_upgrade -from leap.keymanager.keys import ( -    build_key_from_dict, -    KEYMANAGER_KEY_TAG, -    TAGS_PRIVATE_INDEX, -) +from leap.keymanager.keys import build_key_from_dict +from leap.keymanager.documents import KEYMANAGER_KEY_TAG, TAGS_PRIVATE_INDEX  from leap.keymanager.openpgp import OpenPGPScheme  __version__ = get_versions()['version'] diff --git a/keymanager/src/leap/keymanager/documents.py b/keymanager/src/leap/keymanager/documents.py new file mode 100644 index 0000000..2ed5376 --- /dev/null +++ b/keymanager/src/leap/keymanager/documents.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# documents.py +# Copyright (C) 2013-2016 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/>. +""" +Soledad documents +""" +from twisted.internet import defer +from leap.common.check import leap_assert + +# +# Dictionary keys used for storing cryptographic keys. +# + +KEY_VERSION_KEY = 'version' +KEY_UIDS_KEY = 'uids' +KEY_ADDRESS_KEY = 'address' +KEY_TYPE_KEY = 'type' +KEY_FINGERPRINT_KEY = 'fingerprint' +KEY_DATA_KEY = 'key_data' +KEY_PRIVATE_KEY = 'private' +KEY_LENGTH_KEY = 'length' +KEY_EXPIRY_DATE_KEY = 'expiry_date' +KEY_LAST_AUDITED_AT_KEY = 'last_audited_at' +KEY_REFRESHED_AT_KEY = 'refreshed_at' +KEY_VALIDATION_KEY = 'validation' +KEY_ENCR_USED_KEY = 'encr_used' +KEY_SIGN_USED_KEY = 'sign_used' +KEY_TAGS_KEY = 'tags' + + +# +# Key storage constants +# + +KEYMANAGER_KEY_TAG = 'keymanager-key' +KEYMANAGER_ACTIVE_TAG = 'keymanager-active' +KEYMANAGER_ACTIVE_TYPE = '-active' + +# Version of the Soledad Document schema, +# it should be bumped each time the document format changes +KEYMANAGER_DOC_VERSION = 1 + + +# +# key indexing constants. +# + +TAGS_PRIVATE_INDEX = 'by-tags-private' +TYPE_FINGERPRINT_PRIVATE_INDEX = 'by-type-fingerprint-private' +TYPE_ADDRESS_PRIVATE_INDEX = 'by-type-address-private' +INDEXES = { +    TAGS_PRIVATE_INDEX: [ +        KEY_TAGS_KEY, +        'bool(%s)' % KEY_PRIVATE_KEY, +    ], +    TYPE_FINGERPRINT_PRIVATE_INDEX: [ +        KEY_TYPE_KEY, +        KEY_FINGERPRINT_KEY, +        'bool(%s)' % KEY_PRIVATE_KEY, +    ], +    TYPE_ADDRESS_PRIVATE_INDEX: [ +        KEY_TYPE_KEY, +        KEY_ADDRESS_KEY, +        'bool(%s)' % KEY_PRIVATE_KEY, +    ] +} + + +@defer.inlineCallbacks +def init_indexes(soledad): +    """ +    Initialize the database indexes. +    """ +    leap_assert(soledad is not None, +                "Cannot init indexes with null soledad") + +    indexes = yield soledad.list_indexes() +    db_indexes = dict(indexes) +    # Loop through the indexes we expect to find. +    for name, expression in INDEXES.items(): +        if name not in db_indexes: +            # The index does not yet exist. +            yield soledad.create_index(name, *expression) +        elif expression != db_indexes[name]: +            # The index exists but the definition is not what expected, +            # so we delete it and add the proper index expression. +            yield soledad.delete_index(name) +            yield soledad.create_index(name, *expression) diff --git a/keymanager/src/leap/keymanager/keys.py b/keymanager/src/leap/keymanager/keys.py index 296ed86..c0ee21b 100644 --- a/keymanager/src/leap/keymanager/keys.py +++ b/keymanager/src/leap/keymanager/keys.py @@ -27,78 +27,17 @@ import logging  import re  import time -  from datetime import datetime -from leap.common.check import leap_assert -from twisted.internet import defer  from leap.keymanager import errors  from leap.keymanager.wrapper import TempGPGWrapper  from leap.keymanager.validation import ValidationLevels +from leap.keymanager import documents as doc  logger = logging.getLogger(__name__)  # -# Dictionary keys used for storing cryptographic keys. -# - -KEY_VERSION_KEY = 'version' -KEY_UIDS_KEY = 'uids' -KEY_ADDRESS_KEY = 'address' -KEY_TYPE_KEY = 'type' -KEY_FINGERPRINT_KEY = 'fingerprint' -KEY_DATA_KEY = 'key_data' -KEY_PRIVATE_KEY = 'private' -KEY_LENGTH_KEY = 'length' -KEY_EXPIRY_DATE_KEY = 'expiry_date' -KEY_LAST_AUDITED_AT_KEY = 'last_audited_at' -KEY_REFRESHED_AT_KEY = 'refreshed_at' -KEY_VALIDATION_KEY = 'validation' -KEY_ENCR_USED_KEY = 'encr_used' -KEY_SIGN_USED_KEY = 'sign_used' -KEY_TAGS_KEY = 'tags' - - -# -# Key storage constants -# - -KEYMANAGER_KEY_TAG = 'keymanager-key' -KEYMANAGER_ACTIVE_TAG = 'keymanager-active' -KEYMANAGER_ACTIVE_TYPE = '-active' - -# Version of the Soledad Document schema, -# it should be bumped each time the document format changes -KEYMANAGER_DOC_VERSION = 1 - - -# -# key indexing constants. -# - -TAGS_PRIVATE_INDEX = 'by-tags-private' -TYPE_FINGERPRINT_PRIVATE_INDEX = 'by-type-fingerprint-private' -TYPE_ADDRESS_PRIVATE_INDEX = 'by-type-address-private' -INDEXES = { -    TAGS_PRIVATE_INDEX: [ -        KEY_TAGS_KEY, -        'bool(%s)' % KEY_PRIVATE_KEY, -    ], -    TYPE_FINGERPRINT_PRIVATE_INDEX: [ -        KEY_TYPE_KEY, -        KEY_FINGERPRINT_KEY, -        'bool(%s)' % KEY_PRIVATE_KEY, -    ], -    TYPE_ADDRESS_PRIVATE_INDEX: [ -        KEY_TYPE_KEY, -        KEY_ADDRESS_KEY, -        'bool(%s)' % KEY_PRIVATE_KEY, -    ] -} - - -#  # Key handling utilities  # @@ -132,27 +71,27 @@ def build_key_from_dict(key, active=None):      sign_used = False      if active: -        address = active[KEY_ADDRESS_KEY] +        address = active[doc.KEY_ADDRESS_KEY]          try: -            validation = ValidationLevels.get(active[KEY_VALIDATION_KEY]) +            validation = ValidationLevels.get(active[doc.KEY_VALIDATION_KEY])          except ValueError:              logger.error("Not valid validation level (%s) for key %s", -                         (active[KEY_VALIDATION_KEY], -                          active[KEY_FINGERPRINT_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] +                         (active[doc.KEY_VALIDATION_KEY], +                          active[doc.KEY_FINGERPRINT_KEY])) +        last_audited_at = _to_datetime(active[doc.KEY_LAST_AUDITED_AT_KEY]) +        encr_used = active[doc.KEY_ENCR_USED_KEY] +        sign_used = active[doc.KEY_SIGN_USED_KEY] -    expiry_date = _to_datetime(key[KEY_EXPIRY_DATE_KEY]) -    refreshed_at = _to_datetime(key[KEY_REFRESHED_AT_KEY]) +    expiry_date = _to_datetime(key[doc.KEY_EXPIRY_DATE_KEY]) +    refreshed_at = _to_datetime(key[doc.KEY_REFRESHED_AT_KEY])      return OpenPGPKey(          address=address, -        uids=key[KEY_UIDS_KEY], -        fingerprint=key[KEY_FINGERPRINT_KEY], -        key_data=key[KEY_DATA_KEY], -        private=key[KEY_PRIVATE_KEY], -        length=key[KEY_LENGTH_KEY], +        uids=key[doc.KEY_UIDS_KEY], +        fingerprint=key[doc.KEY_FINGERPRINT_KEY], +        key_data=key[doc.KEY_DATA_KEY], +        private=key[doc.KEY_PRIVATE_KEY], +        length=key[doc.KEY_LENGTH_KEY],          expiry_date=expiry_date,          last_audited_at=last_audited_at,          refreshed_at=refreshed_at, @@ -271,16 +210,16 @@ class OpenPGPKey(object):          refreshed_at = _to_unix_time(self.refreshed_at)          return json.dumps({ -            KEY_UIDS_KEY: self.uids, -            KEY_TYPE_KEY: self.__class__.__name__, -            KEY_FINGERPRINT_KEY: self.fingerprint, -            KEY_DATA_KEY: self.key_data, -            KEY_PRIVATE_KEY: self.private, -            KEY_LENGTH_KEY: self.length, -            KEY_EXPIRY_DATE_KEY: expiry_date, -            KEY_REFRESHED_AT_KEY: refreshed_at, -            KEY_VERSION_KEY: KEYMANAGER_DOC_VERSION, -            KEY_TAGS_KEY: [KEYMANAGER_KEY_TAG], +            doc.KEY_UIDS_KEY: self.uids, +            doc.KEY_TYPE_KEY: self.__class__.__name__, +            doc.KEY_FINGERPRINT_KEY: self.fingerprint, +            doc.KEY_DATA_KEY: self.key_data, +            doc.KEY_PRIVATE_KEY: self.private, +            doc.KEY_LENGTH_KEY: self.length, +            doc.KEY_EXPIRY_DATE_KEY: expiry_date, +            doc.KEY_REFRESHED_AT_KEY: refreshed_at, +            doc.KEY_VERSION_KEY: doc.KEYMANAGER_DOC_VERSION, +            doc.KEY_TAGS_KEY: [doc.KEYMANAGER_KEY_TAG],          })      def get_active_json(self): @@ -293,16 +232,17 @@ class OpenPGPKey(object):          last_audited_at = _to_unix_time(self.last_audited_at)          return json.dumps({ -            KEY_ADDRESS_KEY: self.address, -            KEY_TYPE_KEY: self.__class__.__name__ + KEYMANAGER_ACTIVE_TYPE, -            KEY_FINGERPRINT_KEY: self.fingerprint, -            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_VERSION_KEY: KEYMANAGER_DOC_VERSION, -            KEY_TAGS_KEY: [KEYMANAGER_ACTIVE_TAG], +            doc.KEY_ADDRESS_KEY: self.address, +            doc.KEY_TYPE_KEY: (self.__class__.__name__ + +                               doc.KEYMANAGER_ACTIVE_TYPE), +            doc.KEY_FINGERPRINT_KEY: self.fingerprint, +            doc.KEY_PRIVATE_KEY: self.private, +            doc.KEY_VALIDATION_KEY: str(self.validation), +            doc.KEY_LAST_AUDITED_AT_KEY: last_audited_at, +            doc.KEY_ENCR_USED_KEY: self.encr_used, +            doc.KEY_SIGN_USED_KEY: self.sign_used, +            doc.KEY_VERSION_KEY: doc.KEYMANAGER_DOC_VERSION, +            doc.KEY_TAGS_KEY: [doc.KEYMANAGER_ACTIVE_TAG],          })      def next(self): @@ -351,34 +291,3 @@ def parse_address(address):      if match is None:          return None      return ''.join(match.group(2, 4)) - - -def init_indexes(soledad): -    """ -    Initialize the database indexes. -    """ -    leap_assert(soledad is not None, -                "Cannot init indexes with null soledad") - -    def create_idexes(indexes): -        deferreds = [] -        db_indexes = dict(indexes) -        # Loop through the indexes we expect to find. -        for name, expression in INDEXES.items(): -            if name not in db_indexes: -                # The index does not yet exist. -                d = soledad.create_index(name, *expression) -                deferreds.append(d) -            elif expression != db_indexes[name]: -                # The index exists but the definition is not what expected, -                # so we delete it and add the proper index expression. -                d = soledad.delete_index(name) -                d.addCallback( -                    lambda _: -                        soledad.create_index(name, *expression)) -                deferreds.append(d) -        return defer.gatherResults(deferreds, consumeErrors=True) - -    d = soledad.list_indexes() -    d.addCallback(create_idexes) -    return d diff --git a/keymanager/src/leap/keymanager/migrator.py b/keymanager/src/leap/keymanager/migrator.py index 9e4ae77..c73da2e 100644 --- a/keymanager/src/leap/keymanager/migrator.py +++ b/keymanager/src/leap/keymanager/migrator.py @@ -26,21 +26,7 @@ Document migrator  from collections import namedtuple  from twisted.internet.defer import gatherResults, succeed -from leap.keymanager.keys import ( -    TAGS_PRIVATE_INDEX, -    KEYMANAGER_KEY_TAG, -    KEYMANAGER_ACTIVE_TAG, - -    KEYMANAGER_DOC_VERSION, -    KEY_ADDRESS_KEY, -    KEY_UIDS_KEY, -    KEY_VERSION_KEY, -    KEY_FINGERPRINT_KEY, -    KEY_VALIDATION_KEY, -    KEY_LAST_AUDITED_AT_KEY, -    KEY_ENCR_USED_KEY, -    KEY_SIGN_USED_KEY, -) +from leap.keymanager import documents as doc  from leap.keymanager.validation import ValidationLevels @@ -70,12 +56,12 @@ class KeyDocumentsMigrator(object):          private_value = '1' if private else '0'          deferred_keys = self._soledad.get_from_index( -            TAGS_PRIVATE_INDEX, -            KEYMANAGER_KEY_TAG, +            doc.TAGS_PRIVATE_INDEX, +            doc.KEYMANAGER_KEY_TAG,              private_value)          deferred_active = self._soledad.get_from_index( -            TAGS_PRIVATE_INDEX, -            KEYMANAGER_ACTIVE_TAG, +            doc.TAGS_PRIVATE_INDEX, +            doc.KEYMANAGER_ACTIVE_TAG,              private_value)          return gatherResults([deferred_keys, deferred_active]) @@ -99,7 +85,7 @@ class KeyDocumentsMigrator(object):      def _buildKeyDict(self, keys, actives):          keydict = { -            fp2id(key.content[KEY_FINGERPRINT_KEY]): KeyDocs(key, []) +            fp2id(key.content[doc.KEY_FINGERPRINT_KEY]): KeyDocs(key, [])              for key in keys}          deferreds = [] @@ -119,7 +105,7 @@ class KeyDocumentsMigrator(object):      def _filter_outdated(self, keydict):          outdated = {}          for key_id, docs in keydict.items(): -            if ((docs.key and KEY_VERSION_KEY not in docs.key.content) or +            if ((docs.key and doc.KEY_VERSION_KEY not in docs.key.content) or                      docs.active):                  outdated[key_id] = docs          return outdated @@ -136,43 +122,43 @@ class KeyDocumentsMigrator(object):          last_audited = 0          encr_used = False          sign_used = False -        fingerprint = key.content[KEY_FINGERPRINT_KEY] -        if len(actives) == 1 and KEY_VERSION_KEY not in key.content: +        fingerprint = key.content[doc.KEY_FINGERPRINT_KEY] +        if len(actives) == 1 and doc.KEY_VERSION_KEY not in key.content:              # we can preserve the validation of the key if there is only one              # active address for the key -            validation = key.content[KEY_VALIDATION_KEY] -            last_audited = key.content[KEY_LAST_AUDITED_AT_KEY] -            encr_used = key.content[KEY_ENCR_USED_KEY] -            sign_used = key.content[KEY_SIGN_USED_KEY] +            validation = key.content[doc.KEY_VALIDATION_KEY] +            last_audited = key.content[doc.KEY_LAST_AUDITED_AT_KEY] +            encr_used = key.content[doc.KEY_ENCR_USED_KEY] +            sign_used = key.content[doc.KEY_SIGN_USED_KEY]          deferreds = []          for active in actives: -            if KEY_VERSION_KEY in active.content: +            if doc.KEY_VERSION_KEY in active.content:                  continue -            active.content[KEY_VERSION_KEY] = KEYMANAGER_DOC_VERSION -            active.content[KEY_FINGERPRINT_KEY] = fingerprint -            active.content[KEY_VALIDATION_KEY] = validation -            active.content[KEY_LAST_AUDITED_AT_KEY] = last_audited -            active.content[KEY_ENCR_USED_KEY] = encr_used -            active.content[KEY_SIGN_USED_KEY] = sign_used +            active.content[doc.KEY_VERSION_KEY] = doc.KEYMANAGER_DOC_VERSION +            active.content[doc.KEY_FINGERPRINT_KEY] = fingerprint +            active.content[doc.KEY_VALIDATION_KEY] = validation +            active.content[doc.KEY_LAST_AUDITED_AT_KEY] = last_audited +            active.content[doc.KEY_ENCR_USED_KEY] = encr_used +            active.content[doc.KEY_SIGN_USED_KEY] = sign_used              del active.content[KEY_ID_KEY]              d = self._soledad.put_doc(active)              deferreds.append(d)          return gatherResults(deferreds)      def _migrate_key(self, key): -        if not key or KEY_VERSION_KEY in key.content: +        if not key or doc.KEY_VERSION_KEY in key.content:              return succeed(None) -        key.content[KEY_VERSION_KEY] = KEYMANAGER_DOC_VERSION -        key.content[KEY_UIDS_KEY] = key.content[KEY_ADDRESS_KEY] -        del key.content[KEY_ADDRESS_KEY] +        key.content[doc.KEY_VERSION_KEY] = doc.KEYMANAGER_DOC_VERSION +        key.content[doc.KEY_UIDS_KEY] = key.content[doc.KEY_ADDRESS_KEY] +        del key.content[doc.KEY_ADDRESS_KEY]          del key.content[KEY_ID_KEY] -        del key.content[KEY_VALIDATION_KEY] -        del key.content[KEY_LAST_AUDITED_AT_KEY] -        del key.content[KEY_ENCR_USED_KEY] -        del key.content[KEY_SIGN_USED_KEY] +        del key.content[doc.KEY_VALIDATION_KEY] +        del key.content[doc.KEY_LAST_AUDITED_AT_KEY] +        del key.content[doc.KEY_ENCR_USED_KEY] +        del key.content[doc.KEY_SIGN_USED_KEY]          return self._soledad.put_doc(key) diff --git a/keymanager/src/leap/keymanager/openpgp.py b/keymanager/src/leap/keymanager/openpgp.py index fae5600..08b69f7 100644 --- a/keymanager/src/leap/keymanager/openpgp.py +++ b/keymanager/src/leap/keymanager/openpgp.py @@ -36,10 +36,12 @@ from leap.keymanager import errors  from leap.keymanager.wrapper import TempGPGWrapper  from leap.keymanager.keys import (      OpenPGPKey, -    init_indexes,      is_address,      parse_address,      build_key_from_dict, +) +from leap.keymanager.documents import ( +    init_indexes,      TYPE_FINGERPRINT_PRIVATE_INDEX,      TYPE_ADDRESS_PRIVATE_INDEX,      KEY_UIDS_KEY, diff --git a/keymanager/src/leap/keymanager/tests/test_migrator.py b/keymanager/src/leap/keymanager/tests/test_migrator.py index 2d9782b..76323e5 100644 --- a/keymanager/src/leap/keymanager/tests/test_migrator.py +++ b/keymanager/src/leap/keymanager/tests/test_migrator.py @@ -26,7 +26,7 @@ from mock import Mock  from twisted.internet.defer import succeed, inlineCallbacks  from leap.keymanager.migrator import KeyDocumentsMigrator, KEY_ID_KEY -from leap.keymanager.keys import ( +from leap.keymanager.documents import (      TAGS_PRIVATE_INDEX,      KEYMANAGER_ACTIVE_TAG,      KEYMANAGER_KEY_TAG, diff --git a/keymanager/src/leap/keymanager/tests/test_openpgp.py b/keymanager/src/leap/keymanager/tests/test_openpgp.py index 0e39dab..47e9005 100644 --- a/keymanager/src/leap/keymanager/tests/test_openpgp.py +++ b/keymanager/src/leap/keymanager/tests/test_openpgp.py @@ -29,7 +29,7 @@ from leap.keymanager import (      KeyNotFound,      openpgp,  ) -from leap.keymanager.keys import ( +from leap.keymanager.documents import (      TYPE_FINGERPRINT_PRIVATE_INDEX,      TYPE_ADDRESS_PRIVATE_INDEX,  ) @@ -57,7 +57,7 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):              self._soledad, gpgbinary=self.gpg_binary_path)          yield self._assert_key_not_found(pgp, 'user@leap.se')          key = yield pgp.gen_key('user@leap.se') -        self.assertIsInstance(key, openpgp.OpenPGPKey) +        self.assertIsInstance(key, OpenPGPKey)          self.assertEqual(              ['user@leap.se'], key.address, 'Wrong address bound to key.')          self.assertEqual( @@ -80,7 +80,7 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):          yield self._assert_key_not_found(pgp, ADDRESS)          yield pgp.put_raw_key(PUBLIC_KEY, ADDRESS)          key = yield pgp.get_key(ADDRESS, private=False) -        self.assertIsInstance(key, openpgp.OpenPGPKey) +        self.assertIsInstance(key, OpenPGPKey)          self.assertTrue(              ADDRESS in key.address, 'Wrong address bound to key.')          self.assertEqual( | 
