summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/leap/keymanager/__init__.py63
-rw-r--r--src/leap/keymanager/_version.py34
-rw-r--r--src/leap/keymanager/openpgp.py21
-rw-r--r--src/leap/keymanager/tests/test_keymanager.py16
4 files changed, 75 insertions, 59 deletions
diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py
index 6cfbf71..41f352e 100644
--- a/src/leap/keymanager/__init__.py
+++ b/src/leap/keymanager/__init__.py
@@ -23,9 +23,9 @@ import sys
try:
from gnupg.gnupg import GPGUtilities
assert(GPGUtilities) # pyflakes happy
- from gnupg import __version__
- from distutils.version import LooseVersion as V
- assert(V(__version__) >= V('1.2.3'))
+ from gnupg import __version__ as _gnupg_version
+ from pkg_resources import parse_version
+ assert(parse_version(_gnupg_version) >= parse_version('1.2.3'))
except (ImportError, AssertionError):
print "*******"
@@ -46,6 +46,7 @@ import requests
from leap.common.check import leap_assert, leap_assert_type
from leap.common.events import signal
from leap.common.events import events_pb2 as proto
+from leap.common.decorators import memoized_method
from leap.keymanager.errors import KeyNotFound
@@ -76,7 +77,7 @@ class KeyManager(object):
OPENPGP_KEY = 'openpgp'
PUBKEY_KEY = "user[public_key]"
- def __init__(self, address, nickserver_uri, soledad, session_id=None,
+ def __init__(self, address, nickserver_uri, soledad, token=None,
ca_cert_path=None, api_uri=None, api_version=None, uid=None,
gpgbinary=None):
"""
@@ -89,8 +90,8 @@ class KeyManager(object):
:type url: str
:param soledad: A Soledad instance for local storage of keys.
:type soledad: leap.soledad.Soledad
- :param session_id: The session ID for interacting with the webapp API.
- :type session_id: str
+ :param token: The token for interacting with the webapp API.
+ :type token: str
:param ca_cert_path: The path to the CA certificate.
:type ca_cert_path: str
:param api_uri: The URI of the webapp API.
@@ -105,7 +106,7 @@ class KeyManager(object):
self._address = address
self._nickserver_uri = nickserver_uri
self._soledad = soledad
- self._session_id = session_id
+ self._token = token
self.ca_cert_path = ca_cert_path
self.api_uri = api_uri
self.api_version = api_version
@@ -179,11 +180,11 @@ class KeyManager(object):
self._ca_cert_path is not None,
'We need the CA certificate path!')
leap_assert(
- self._session_id is not None,
- 'We need a session_id to interact with webapp!')
+ self._token is not None,
+ 'We need a token to interact with webapp!')
res = self._fetcher.put(
uri, data=data, verify=self._ca_cert_path,
- cookies={'_session_id': self._session_id})
+ headers={'Authorization': 'Token token=%s' % self._token})
# assert that the response is valid
res.raise_for_status()
return res
@@ -196,21 +197,25 @@ class KeyManager(object):
:param address: The address bound to the keys.
:type address: str
- @raise KeyNotFound: If the key was not found on nickserver.
+ :raise KeyNotFound: If the key was not found on nickserver.
"""
# request keys from the nickserver
res = None
try:
res = self._get(self._nickserver_uri, {'address': address})
+ res.raise_for_status()
server_keys = res.json()
# insert keys in local database
if self.OPENPGP_KEY in server_keys:
self._wrapper_map[OpenPGPKey].put_ascii_key(
server_keys['openpgp'])
+ except requests.exceptions.HTTPError as e:
+ if e.response.status_code == 404:
+ raise KeyNotFound(address)
+ logger.warning("HTTP error retrieving key: %r" % (e,))
+ logger.warning("%s" % (res.content,))
except Exception as e:
- logger.warning("Error retrieving the keys: %r" % (e,))
- if res:
- logger.warning("%s" % (res.content,))
+ logger.warning("Error retrieving key: %r" % (e,))
#
# key management
@@ -232,7 +237,7 @@ class KeyManager(object):
:param ktype: The type of the key.
:type ktype: KeyType
- @raise KeyNotFound: If the key was not found in local database.
+ :raise KeyNotFound: If the key was not found in local database.
"""
leap_assert(
ktype is OpenPGPKey,
@@ -250,6 +255,13 @@ class KeyManager(object):
self._put(uri, data)
signal(proto.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
+ @memoized_method
+ def get_key_from_cache(self, *args, **kwargs):
+ """
+ Public interface to `get_key`, that is memoized.
+ """
+ return self.get_key(*args, **kwargs)
+
def get_key(self, address, ktype, private=False, fetch_remote=True):
"""
Return a key of type C{ktype} bound to C{address}.
@@ -266,9 +278,10 @@ class KeyManager(object):
:return: A key of type C{ktype} bound to C{address}.
:rtype: EncryptionKey
- @raise KeyNotFound: If the key was not found both locally and in
- keyserver.
+ :raise KeyNotFound: If the key was not found both locally and in
+ keyserver.
"""
+ logger.debug("getting key for %s" % (address,))
leap_assert(
ktype in self._wrapper_map,
'Unkown key type: %s.' % str(ktype))
@@ -288,7 +301,7 @@ class KeyManager(object):
raise
signal(proto.KEYMANAGER_LOOKING_FOR_KEY, address)
- self._fetch_keys_from_server(address)
+ self._fetch_keys_from_server(address) # might raise KeyNotFound
key = self._wrapper_map[ktype].get_key(address, private=False)
signal(proto.KEYMANAGER_KEY_FOUND, address)
@@ -344,14 +357,14 @@ class KeyManager(object):
# Setters/getters
#
- def _get_session_id(self):
- return self._session_id
+ def _get_token(self):
+ return self._token
- def _set_session_id(self, session_id):
- self._session_id = session_id
+ def _set_token(self, token):
+ self._token = token
- session_id = property(
- _get_session_id, _set_session_id, doc='The session id.')
+ token = property(
+ _get_token, _set_token, doc='The session token.')
def _get_ca_cert_path(self):
return self._ca_cert_path
@@ -434,7 +447,7 @@ class KeyManager(object):
:return: The decrypted data.
:rtype: str
- @raise InvalidSignature: Raised if unable to verify the signature with
+ :raise InvalidSignature: Raised if unable to verify the signature with
C{verify} key.
"""
leap_assert_type(privkey, EncryptionKey)
diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py
index 3a514e1..28fca96 100644
--- a/src/leap/keymanager/_version.py
+++ b/src/leap/keymanager/_version.py
@@ -17,6 +17,7 @@ git_full = "$Format:%H$"
import subprocess
import sys
+
def run_command(args, cwd=None, verbose=False):
try:
# remember shell=False, so use git.cmd on windows, not just git
@@ -37,10 +38,10 @@ def run_command(args, cwd=None, verbose=False):
return stdout
-import sys
import re
import os.path
+
def get_expanded_variables(versionfile_source):
# the code embedded in _version.py can just fetch the value of these
# variables. When used from setup.py, we don't want to import
@@ -48,7 +49,7 @@ def get_expanded_variables(versionfile_source):
# used from _version.py.
variables = {}
try:
- f = open(versionfile_source,"r")
+ f = open(versionfile_source, "r")
for line in f.readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
@@ -63,12 +64,13 @@ def get_expanded_variables(versionfile_source):
pass
return variables
+
def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
refnames = variables["refnames"].strip()
if refnames.startswith("$Format"):
if verbose:
print("variables are unexpanded, not using")
- return {} # unexpanded, so not in an unpacked git-archive tarball
+ return {} # unexpanded, so not in an unpacked git-archive tarball
refs = set([r.strip() for r in refnames.strip("()").split(",")])
# 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.
@@ -93,13 +95,14 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False):
r = ref[len(tag_prefix):]
if verbose:
print("picking %s" % r)
- return { "version": r,
- "full": variables["full"].strip() }
+ return {"version": r,
+ "full": variables["full"].strip()}
# no suitable tags, so we use the full revision id
if verbose:
print("no suitable tags, using full revision id")
- return { "version": variables["full"].strip(),
- "full": variables["full"].strip() }
+ return {"version": variables["full"].strip(),
+ "full": variables["full"].strip()}
+
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
# this runs 'git' from the root of the source tree. That either means
@@ -116,7 +119,7 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
here = os.path.abspath(__file__)
except NameError:
# some py2exe/bbfreeze/non-CPython implementations don't do __file__
- return {} # not always correct
+ return {} # not always correct
# versionfile_source is the relative path from the top of the source tree
# (where the .git directory might live) to this file. Invert this to find
@@ -141,7 +144,8 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
return {}
if not stdout.startswith(tag_prefix):
if verbose:
- print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix))
+ print("tag '%s' doesn't start with prefix '%s'" %
+ (stdout, tag_prefix))
return {}
tag = stdout[len(tag_prefix):]
stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root)
@@ -153,7 +157,8 @@ def versions_from_vcs(tag_prefix, versionfile_source, verbose=False):
return {"version": tag, "full": full}
-def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False):
+def versions_from_parentdir(parentdir_prefix, versionfile_source,
+ verbose=False):
if IN_LONG_VERSION_PY:
# We're running from _version.py. If it's from a source tree
# (execute-in-place), we can work upwards to find the root of the
@@ -163,7 +168,7 @@ def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False)
here = os.path.abspath(__file__)
except NameError:
# py2exe/bbfreeze/non-CPython don't have __file__
- return {} # without __file__, we have no hope
+ return {} # without __file__, we have no hope
# versionfile_source is the relative path from the top of the source
# tree to _version.py. Invert this to find the root from __file__.
root = here
@@ -180,7 +185,8 @@ def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False)
dirname = os.path.basename(root)
if not dirname.startswith(parentdir_prefix):
if verbose:
- print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" %
+ print("guessing rootdir is '%s', but '%s' doesn't start "
+ "with prefix '%s'" %
(root, dirname, parentdir_prefix))
return None
return {"version": dirname[len(parentdir_prefix):], "full": ""}
@@ -189,8 +195,9 @@ tag_prefix = ""
parentdir_prefix = "leap.keymanager-"
versionfile_source = "src/leap/keymanager/_version.py"
+
def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
- variables = { "refnames": git_refnames, "full": git_full }
+ variables = {"refnames": git_refnames, "full": git_full}
ver = versions_from_expanded_variables(variables, tag_prefix, verbose)
if not ver:
ver = versions_from_vcs(tag_prefix, versionfile_source, verbose)
@@ -200,4 +207,3 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False):
if not ver:
ver = default
return ver
-
diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py
index 856b21e..950d022 100644
--- a/src/leap/keymanager/openpgp.py
+++ b/src/leap/keymanager/openpgp.py
@@ -14,19 +14,13 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
"""
Infrastructure for using OpenPGP keys in Key Manager.
"""
-
-
-import locale
import logging
import os
import re
import shutil
-import sys
import tempfile
from contextlib import closing
@@ -298,7 +292,7 @@ class OpenPGPScheme(EncryptionScheme):
@raise KeyNotFound: If the key was not found on local storage.
"""
# Remove the identity suffix after the '+' until the '@'
- # e.g.: test_user+something@provider.com becomes test_user@probider.com
+ # e.g.: test_user+something@provider.com becomes test_user@provider.com
# since the key belongs to the identity without the '+' suffix.
address = re.sub(r'\+.*\@', '@', address)
@@ -526,7 +520,7 @@ class OpenPGPScheme(EncryptionScheme):
return result.data
except errors.GPGError as e:
logger.error('Failed to decrypt: %s.' % str(e))
- raise error.EncryptError()
+ raise errors.EncryptError()
def decrypt(self, data, privkey, passphrase=None, verify=None):
"""
@@ -568,20 +562,11 @@ class OpenPGPScheme(EncryptionScheme):
'Failed to verify signature with key %s: %s' %
(verify.key_id, result.stderr))
- # XXX: this is the encoding used by gpg module
- # https://github.com/isislovecruft/python-gnupg/\
- # blob/master/gnupg/_meta.py#L121
- encoding = locale.getpreferredencoding()
- if encoding is None:
- encoding = sys.stdin.encoding
- if encoding is None:
- encoding = 'utf-8'
- return result.data.decode(encoding, 'replace')
+ return result.data
except errors.GPGError as e:
logger.error('Failed to decrypt: %s.' % str(e))
raise errors.DecryptError(str(e))
-
def is_encrypted(self, data):
"""
Return whether C{data} was asymmetrically encrypted using OpenPGP.
diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py
index 67676e9..e2558e4 100644
--- a/src/leap/keymanager/tests/test_keymanager.py
+++ b/src/leap/keymanager/tests/test_keymanager.py
@@ -118,9 +118,21 @@ class KeyManagerWithSoledadTestCase(BaseLeapTest):
Soledad._get_secrets_from_shared_db = Mock(return_value=None)
Soledad._put_secrets_in_shared_db = Mock(return_value=None)
+ class MockSharedDB(object):
+
+ get_doc = Mock(return_value=None)
+ put_doc = Mock()
+ lock = Mock(return_value=('atoken', 300))
+ unlock = Mock(return_value=True)
+
+ def __call__(self):
+ return self
+
+ Soledad._shared_db = MockSharedDB()
+
self._soledad = Soledad(
- "leap@leap.se",
- "123456",
+ u"leap@leap.se",
+ u"123456",
secrets_path=self.tempdir + "/secret.gpg",
local_db_path=self.tempdir + "/soledad.u1db",
server_url='',