From ddf5c623c46af4b2c28a34fed4ccc0581fe44d52 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 30 Oct 2013 15:50:04 -0200 Subject: 0.3.4 version freeze --- src/leap/keymanager/_version.py | 208 ++-------------------------------------- 1 file changed, 9 insertions(+), 199 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 3a514e1..5b2394a 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -1,203 +1,13 @@ -IN_LONG_VERSION_PY = True -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (build by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. +# This file was generated by the `freeze_debianver` command in setup.py +# Using 'versioneer.py' (0.7+) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. -# This file is released into the public domain. Generated by -# versioneer-0.7+ (https://github.com/warner/python-versioneer) +version_version = '0.3.4' +version_full = '7d5e93253271ef10a0c497ff8e27ce597f6086e4' -# these strings will be replaced by git during git-archive -git_refnames = "$Format:%d$" -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 - p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) - except EnvironmentError: - e = sys.exc_info()[1] - if verbose: - print("unable to run %s" % args[0]) - print(e) - return None - stdout = p.communicate()[0].strip() - if sys.version >= '3': - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % args[0]) - return None - 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 - # _version.py, so we do it with a regexp instead. This function is not - # used from _version.py. - variables = {} - try: - f = open(versionfile_source,"r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["full"] = mo.group(1) - f.close() - except EnvironmentError: - 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 - 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. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs-tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - 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() } - -def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): - # this runs 'git' from the root of the source tree. That either means - # someone ran a setup.py command (and this code is in versioneer.py, so - # IN_LONG_VERSION_PY=False, thus the containing directory is the root of - # the source tree), or someone ran a project-specific entry point (and - # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the - # containing directory is somewhere deeper in the source tree). This only - # gets called if the git-archive 'subst' variables were *not* expanded, - # and _version.py hasn't already been rewritten with a short version - # string, meaning we're inside a checked out source tree. - - try: - here = os.path.abspath(__file__) - except NameError: - # some py2exe/bbfreeze/non-CPython implementations don't do __file__ - 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 - # the root from __file__. - root = here - if IN_LONG_VERSION_PY: - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - root = os.path.dirname(here) - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %s" % root) - return {} - - GIT = "git" - if sys.platform == "win32": - GIT = "git.cmd" - stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], - cwd=root) - if stdout is None: - return {} - if not stdout.startswith(tag_prefix): - if verbose: - 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) - if stdout is None: - return {} - full = stdout.strip() - if tag.endswith("-dirty"): - full += "-dirty" - return {"version": tag, "full": full} - - -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 - # tree, and then check the parent directory for a version string. If - # it's in an installed application, there's no hope. - try: - here = os.path.abspath(__file__) - except NameError: - # py2exe/bbfreeze/non-CPython don't have __file__ - 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 - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - # we're running from versioneer.py, which means we're running from - # the setup.py in a source tree. sys.argv[0] is setup.py in the root. - here = os.path.abspath(sys.argv[0]) - root = os.path.dirname(here) - - # Source tarballs conventionally unpack into a directory that includes - # both the project name and a version string. - 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'" % - (root, dirname, parentdir_prefix)) - return None - return {"version": dirname[len(parentdir_prefix):], "full": ""} - -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 } - ver = versions_from_expanded_variables(variables, tag_prefix, verbose) - if not ver: - ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) - if not ver: - ver = versions_from_parentdir(parentdir_prefix, versionfile_source, - verbose) - if not ver: - ver = default - return ver +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} -- cgit v1.2.3 From e7e64a88ac65917bd8950b0ce16aad949823f7c6 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 5 Nov 2013 11:15:30 -0200 Subject: freeze debian ver to 0.3.5 --- src/leap/keymanager/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 5b2394a..2d4f99c 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,8 +5,8 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.3.4' -version_full = '7d5e93253271ef10a0c497ff8e27ce597f6086e4' +version_version = '0.3.5' +version_full = 'f29288cef742aa68c502493582de454715d98595' def get_versions(default={}, verbose=False): -- cgit v1.2.3 From 99ee292afceac503f96689906351b84ca64265b7 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Fri, 15 Nov 2013 23:34:09 -0200 Subject: freeze debian version --- src/leap/keymanager/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 2d4f99c..e0fb020 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,8 +5,8 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.3.5' -version_full = 'f29288cef742aa68c502493582de454715d98595' +version_version = '0.3.6' +version_full = 'f5de4bdecb24664ec1f3ba1172829bcad32f3abc' def get_versions(default={}, verbose=False): -- cgit v1.2.3 From 3ae3c8153b8f4237470b1f46bd6f545215c3cd0a Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 10 Dec 2013 15:47:59 -0400 Subject: freeze debian version --- src/leap/keymanager/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index e0fb020..6beeff5 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,8 +5,8 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.3.6' -version_full = 'f5de4bdecb24664ec1f3ba1172829bcad32f3abc' +version_version = '0.3.7' +version_full = 'ee2bedef370e9a229ef1805a336c35d967f0abdf' def get_versions(default={}, verbose=False): -- cgit v1.2.3 From d7efe9e5c802db08bdb0a75c168527572cbdf255 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 23 Dec 2013 02:22:34 -0400 Subject: freeze debian version to 0.3.8-rc1 --- src/leap/keymanager/_version.py | 214 ++-------------------------------------- 1 file changed, 9 insertions(+), 205 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 28fca96..de3a5a2 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -1,209 +1,13 @@ -IN_LONG_VERSION_PY = True -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (build by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. +# This file was generated by the `freeze_debianver` command in setup.py +# Using 'versioneer.py' (0.7+) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. -# This file is released into the public domain. Generated by -# versioneer-0.7+ (https://github.com/warner/python-versioneer) +version_version = '0.3.8-rc1' +version_full = '0929d3953191e7ad5ec51f3e94ad6d7608428d48' -# these strings will be replaced by git during git-archive -git_refnames = "$Format:%d$" -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 - p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) - except EnvironmentError: - e = sys.exc_info()[1] - if verbose: - print("unable to run %s" % args[0]) - print(e) - return None - stdout = p.communicate()[0].strip() - if sys.version >= '3': - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % args[0]) - return None - return stdout - - -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 - # _version.py, so we do it with a regexp instead. This function is not - # used from _version.py. - variables = {} - try: - f = open(versionfile_source, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - variables["full"] = mo.group(1) - f.close() - except EnvironmentError: - 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 - 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. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs-tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - 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()} - - -def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): - # this runs 'git' from the root of the source tree. That either means - # someone ran a setup.py command (and this code is in versioneer.py, so - # IN_LONG_VERSION_PY=False, thus the containing directory is the root of - # the source tree), or someone ran a project-specific entry point (and - # this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the - # containing directory is somewhere deeper in the source tree). This only - # gets called if the git-archive 'subst' variables were *not* expanded, - # and _version.py hasn't already been rewritten with a short version - # string, meaning we're inside a checked out source tree. - - try: - here = os.path.abspath(__file__) - except NameError: - # some py2exe/bbfreeze/non-CPython implementations don't do __file__ - 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 - # the root from __file__. - root = here - if IN_LONG_VERSION_PY: - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - root = os.path.dirname(here) - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %s" % root) - return {} - - GIT = "git" - if sys.platform == "win32": - GIT = "git.cmd" - stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], - cwd=root) - if stdout is None: - return {} - if not stdout.startswith(tag_prefix): - if verbose: - 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) - if stdout is None: - return {} - full = stdout.strip() - if tag.endswith("-dirty"): - full += "-dirty" - return {"version": tag, "full": full} - - -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 - # tree, and then check the parent directory for a version string. If - # it's in an installed application, there's no hope. - try: - here = os.path.abspath(__file__) - except NameError: - # py2exe/bbfreeze/non-CPython don't have __file__ - 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 - for i in range(len(versionfile_source.split("/"))): - root = os.path.dirname(root) - else: - # we're running from versioneer.py, which means we're running from - # the setup.py in a source tree. sys.argv[0] is setup.py in the root. - here = os.path.abspath(sys.argv[0]) - root = os.path.dirname(here) - - # Source tarballs conventionally unpack into a directory that includes - # both the project name and a version string. - 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'" % - (root, dirname, parentdir_prefix)) - return None - return {"version": dirname[len(parentdir_prefix):], "full": ""} - -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} - ver = versions_from_expanded_variables(variables, tag_prefix, verbose) - if not ver: - ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) - if not ver: - ver = versions_from_parentdir(parentdir_prefix, versionfile_source, - verbose) - if not ver: - ver = default - return ver +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} -- cgit v1.2.3 From 94ccb31a9e7e90caffb1ded4c34baf804ccf31f9 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 9 Apr 2014 14:41:26 -0500 Subject: bump debian ver to 0.3.8 --- src/leap/keymanager/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index de3a5a2..ad54645 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,7 +5,7 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.3.8-rc1' +version_version = '0.3.8' version_full = '0929d3953191e7ad5ec51f3e94ad6d7608428d48' -- cgit v1.2.3 From d7acaf356d16c795f1481fefc7a75ffc8a36b1d0 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Fri, 26 Jun 2015 18:12:22 +0200 Subject: [bug] remove the dependency on enum34 * Resolves: #7188 --- src/leap/keymanager/__init__.py | 14 +++--- src/leap/keymanager/keys.py | 10 ++-- src/leap/keymanager/tests/test_keymanager.py | 13 ++--- src/leap/keymanager/tests/test_validation.py | 18 +++---- src/leap/keymanager/validation.py | 73 +++++++++++++++++++--------- 5 files changed, 77 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 47f479b..c2d7409 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -57,7 +57,7 @@ from leap.keymanager.errors import ( UnsupportedKeyTypeError, InvalidSignature ) -from leap.keymanager.validation import ValidationLevel, can_upgrade +from leap.keymanager.validation import ValidationLevels, can_upgrade from leap.keymanager.keys import ( build_key_from_dict, @@ -224,10 +224,10 @@ class KeyManager(object): if self.OPENPGP_KEY in server_keys: # nicknym server is authoritative for its own domain, # for other domains the key might come from key servers. - validation_level = ValidationLevel.Weak_Chain + validation_level = ValidationLevels.Weak_Chain _, domain = _split_email(address) if (domain == _get_domain(self._nickserver_uri)): - validation_level = ValidationLevel.Provider_Trust + validation_level = ValidationLevels.Provider_Trust d = self.put_raw_key( server_keys['openpgp'], @@ -712,7 +712,7 @@ class KeyManager(object): return d def put_raw_key(self, key, ktype, address, - validation=ValidationLevel.Weak_Chain): + validation=ValidationLevels.Weak_Chain): """ Put raw key bound to address in local storage. @@ -724,7 +724,7 @@ class KeyManager(object): :type address: str :param validation: validation level for this key (default: 'Weak_Chain') - :type validation: ValidationLevel + :type validation: ValidationLevels :return: A Deferred which fires when the key is in the storage, or which fails with KeyAddressMismatch if address doesn't match @@ -744,7 +744,7 @@ class KeyManager(object): return d def fetch_key(self, address, uri, ktype, - validation=ValidationLevel.Weak_Chain): + validation=ValidationLevels.Weak_Chain): """ Fetch a public key bound to address from the network and put it in local storage. @@ -757,7 +757,7 @@ class KeyManager(object): :type ktype: subclass of EncryptionKey :param validation: validation level for this key (default: 'Weak_Chain') - :type validation: ValidationLevel + :type validation: ValidationLevels :return: A Deferred which fires when the key is in the storage, or which fails with KeyNotFound: if not valid key on uri or fails diff --git a/src/leap/keymanager/keys.py b/src/leap/keymanager/keys.py index 562c0a9..91559c2 100644 --- a/src/leap/keymanager/keys.py +++ b/src/leap/keymanager/keys.py @@ -35,7 +35,7 @@ from datetime import datetime from leap.common.check import leap_assert from twisted.internet import defer -from leap.keymanager.validation import ValidationLevel, toValidationLevel +from leap.keymanager.validation import ValidationLevels logger = logging.getLogger(__name__) @@ -120,11 +120,11 @@ def build_key_from_dict(kClass, kdict): :rtype: C{kClass} """ try: - validation = toValidationLevel(kdict[KEY_VALIDATION_KEY]) + 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 = ValidationLevel.Weak_Chain + validation = ValidationLevels.Weak_Chain expiry_date = _to_datetime(kdict[KEY_EXPIRY_DATE_KEY]) last_audited_at = _to_datetime(kdict[KEY_LAST_AUDITED_AT_KEY]) @@ -176,7 +176,7 @@ class EncryptionKey(object): def __init__(self, address, key_id="", fingerprint="", key_data="", private=False, length=0, expiry_date=None, - validation=ValidationLevel.Weak_Chain, last_audited_at=None, + validation=ValidationLevels.Weak_Chain, last_audited_at=None, refreshed_at=None, encr_used=False, sign_used=False): self.address = address self.key_id = key_id @@ -213,7 +213,7 @@ class EncryptionKey(object): KEY_EXPIRY_DATE_KEY: expiry_date, KEY_LAST_AUDITED_AT_KEY: last_audited_at, KEY_REFRESHED_AT_KEY: refreshed_at, - KEY_VALIDATION_KEY: self.validation.name, + 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], diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 55f892e..08d3750 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -36,10 +36,7 @@ from leap.keymanager.keys import ( is_address, build_key_from_dict, ) -from leap.keymanager.validation import ( - ValidationLevel, - toValidationLevel -) +from leap.keymanager.validation import ValidationLevels from leap.keymanager.tests import ( KeyManagerWithSoledadTestCase, ADDRESS, @@ -82,7 +79,7 @@ class KeyManagerUtilTestCase(unittest.TestCase): 'expiry_date': 0, 'last_audited_at': 0, 'refreshed_at': 1311239602, - 'validation': ValidationLevel.Weak_Chain.name, + 'validation': str(ValidationLevels.Weak_Chain), 'encr_used': False, 'sign_used': True, } @@ -115,7 +112,7 @@ class KeyManagerUtilTestCase(unittest.TestCase): datetime.fromtimestamp(kdict['refreshed_at']), key.refreshed_at, 'Wrong data in key.') self.assertEqual( - toValidationLevel(kdict['validation']), key.validation, + ValidationLevels.get(kdict['validation']), key.validation, 'Wrong data in key.') self.assertEqual( kdict['encr_used'], key.encr_used, @@ -227,7 +224,7 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): key = yield self._fetch_key(km, ADDRESS, PUBLIC_KEY) self.assertIsInstance(key, OpenPGPKey) self.assertTrue(ADDRESS in key.address) - self.assertEqual(key.validation, ValidationLevel.Provider_Trust) + self.assertEqual(key.validation, ValidationLevels.Provider_Trust) @inlineCallbacks def test_get_key_fetches_other_domain(self): @@ -239,7 +236,7 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): key = yield self._fetch_key(km, ADDRESS_OTHER, PUBLIC_KEY_OTHER) self.assertIsInstance(key, OpenPGPKey) self.assertTrue(ADDRESS_OTHER in key.address) - self.assertEqual(key.validation, ValidationLevel.Weak_Chain) + self.assertEqual(key.validation, ValidationLevels.Weak_Chain) def _fetch_key(self, km, address, key): """ diff --git a/src/leap/keymanager/tests/test_validation.py b/src/leap/keymanager/tests/test_validation.py index 15e7d27..0c1d155 100644 --- a/src/leap/keymanager/tests/test_validation.py +++ b/src/leap/keymanager/tests/test_validation.py @@ -31,10 +31,10 @@ from leap.keymanager.tests import ( PUBLIC_KEY, KEY_FINGERPRINT ) -from leap.keymanager.validation import ValidationLevel +from leap.keymanager.validation import ValidationLevels -class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): +class ValidationLevelsTestCase(KeyManagerWithSoledadTestCase): @inlineCallbacks def test_none_old_key(self): @@ -47,7 +47,7 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): def test_cant_upgrade(self): km = self._key_manager() yield km.put_raw_key(PUBLIC_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Provider_Trust) + validation=ValidationLevels.Provider_Trust) d = km.put_raw_key(UNRELATED_KEY, OpenPGPKey, ADDRESS) yield self.assertFailure(d, KeyNotValidUpgrade) @@ -56,7 +56,7 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): km = self._key_manager() yield km.put_raw_key(PUBLIC_KEY, OpenPGPKey, ADDRESS) yield km.put_raw_key(UNRELATED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Fingerprint) + validation=ValidationLevels.Fingerprint) key = yield km.get_key(ADDRESS, OpenPGPKey, fetch_remote=False) self.assertEqual(key.fingerprint, UNRELATED_FINGERPRINT) @@ -73,12 +73,12 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): km = self._key_manager() yield km.put_raw_key( EXPIRED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Third_Party_Endorsement) + validation=ValidationLevels.Third_Party_Endorsement) d = km.put_raw_key( UNRELATED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Provider_Trust) + validation=ValidationLevels.Provider_Trust) yield self.assertFailure(d, KeyNotValidUpgrade) @inlineCallbacks @@ -93,9 +93,9 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): def test_not_used(self): km = self._key_manager() yield km.put_raw_key(UNEXPIRED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Provider_Trust) + validation=ValidationLevels.Provider_Trust) yield km.put_raw_key(UNRELATED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Provider_Endorsement) + validation=ValidationLevels.Provider_Endorsement) key = yield km.get_key(ADDRESS, OpenPGPKey, fetch_remote=False) self.assertEqual(key.fingerprint, UNRELATED_FINGERPRINT) @@ -114,7 +114,7 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): yield km.verify(TEXT, ADDRESS, OpenPGPKey, detached_sig=signature) d = km.put_raw_key( UNRELATED_KEY, OpenPGPKey, ADDRESS, - validation=ValidationLevel.Provider_Endorsement) + validation=ValidationLevels.Provider_Endorsement) yield self.assertFailure(d, KeyNotValidUpgrade) @inlineCallbacks diff --git a/src/leap/keymanager/validation.py b/src/leap/keymanager/validation.py index dfe6432..3bb4032 100644 --- a/src/leap/keymanager/validation.py +++ b/src/leap/keymanager/validation.py @@ -24,34 +24,63 @@ See: from datetime import datetime -from enum import IntEnum -ValidationLevel = IntEnum("ValidationLevel", - "Weak_Chain " - "Provider_Trust " - "Provider_Endorsement " - "Third_Party_Endorsement " - "Third_Party_Consensus " - "Historically_Auditing " - "Known_Key " - "Fingerprint") +class ValidationLevel(object): + """ + A validation level + + Meant to be used to compare levels or get it's string representation. + """ + def __init__(self, name, value): + self.name = name + self.value = value + + def __cmp__(self, other): + return cmp(self.value, other.value) + + def __str__(self): + return self.name + + def __repr__(self): + return "" % (self.name, self.value) -def toValidationLevel(value): +class _ValidationLevels(object): """ - Convert a string representation of a validation level into - C{ValidationLevel} + Handler class to manage validation levels. It should have only one global + instance 'ValidationLevels'. - :param value: validation level - :type value: str - :rtype: ValidationLevel - :raises ValueError: if C{value} is not a validation level + The levels are attributes of the instance and can be used like: + ValidationLevels.Weak_Chain + ValidationLevels.get("Weak_Chain") """ - for level in ValidationLevel: - if value == level.name: - return level - raise ValueError("Not valid validation level: %s" % (value,)) + _level_names = ("Weak_Chain", + "Provider_Trust", + "Provider_Endorsement", + "Third_Party_Endorsement", + "Third_Party_Consensus", + "Historically_Auditing", + "Known_Key", + "Fingerprint") + + def __init__(self): + for name in self._level_names: + setattr(self, name, + ValidationLevel(name, self._level_names.index(name))) + + def get(self, name): + """ + Get the ValidationLevel of a name + + :param name: name of the level + :type name: str + :rtype: ValidationLevel + """ + return getattr(self, name) + + +ValidationLevels = _ValidationLevels() def can_upgrade(new_key, old_key): @@ -69,7 +98,7 @@ def can_upgrade(new_key, old_key): return True # Manually verified fingerprint - if new_key.validation == ValidationLevel.Fingerprint: + if new_key.validation == ValidationLevels.Fingerprint: return True # Expired key and higher validation level -- cgit v1.2.3 From ec0757c5972588d05224ea2d56d75ee9cd57c41f Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 29 Jun 2015 12:05:51 -0400 Subject: [style] spelling typo --- src/leap/keymanager/validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/validation.py b/src/leap/keymanager/validation.py index 3bb4032..734cfce 100644 --- a/src/leap/keymanager/validation.py +++ b/src/leap/keymanager/validation.py @@ -30,7 +30,7 @@ class ValidationLevel(object): """ A validation level - Meant to be used to compare levels or get it's string representation. + Meant to be used to compare levels or get its string representation. """ def __init__(self, name, value): self.name = name -- cgit v1.2.3 From 8d355cabd0b087b5e7161c2721bb8ae94ace1336 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 23 Jul 2015 14:34:53 -0400 Subject: [pkg] avoid choking on latest gnupg version latest gnupg version (from pypi) was '2.0.2-py2.7.egg', which is parsed as a LegacyVersion and therefore breaks the numeric comparison. this is a workaround to allow the sanity check to continue, by comparing just the numeric part of the version string. --- src/leap/keymanager/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index c2d7409..56633c5 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -24,13 +24,20 @@ try: from gnupg.gnupg import GPGUtilities assert(GPGUtilities) # pyflakes happy from gnupg import __version__ as _gnupg_version + if '-' in _gnupg_version: + # avoid Parsing it as LegacyVersion, get just + # the release numbers: + _gnupg_version = _gnupg_version.split('-')[0] from pkg_resources import parse_version + # We need to make sure that we're not colliding with the infamous + # python-gnupg assert(parse_version(_gnupg_version) >= parse_version('1.4.0')) except (ImportError, AssertionError): print "*******" print "Ooops! It looks like there is a conflict in the installed version " print "of gnupg." + print "GNUPG_VERSION:", _gnupg_version print print "Disclaimer: Ideally, we would need to work a patch and propose the " print "merge to upstream. But until then do: " -- cgit v1.2.3 From 5c967b8c236900f93147b7d286a080d650a9e5d0 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 29 Jul 2015 16:27:54 -0400 Subject: [style] pep8 --- src/leap/keymanager/__init__.py | 15 ++++++--------- src/leap/keymanager/tests/test_keymanager.py | 3 +-- src/leap/keymanager/tests/test_validation.py | 3 +-- 3 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 56633c5..282ff48 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -71,10 +71,12 @@ from leap.keymanager.keys import ( KEYMANAGER_KEY_TAG, TAGS_PRIVATE_INDEX, ) -from leap.keymanager.openpgp import ( - OpenPGPKey, - OpenPGPScheme, -) +from leap.keymanager.openpgp import OpenPGPKey, OpenPGPScheme + +from ._version import get_versions + +__version__ = get_versions()['version'] +del get_versions logger = logging.getLogger(__name__) @@ -828,8 +830,3 @@ def _get_domain(url): :rtype: str """ return urlparse(url).hostname - - -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 08d3750..a12cac0 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -388,9 +388,8 @@ class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): sign=ADDRESS, fetch_remote=False)) return self.assertFailure(d, KeyNotFound) - -import unittest if __name__ == "__main__": + import unittest unittest.main() # key 0F91B402: someone@somedomain.org diff --git a/src/leap/keymanager/tests/test_validation.py b/src/leap/keymanager/tests/test_validation.py index 0c1d155..561ca50 100644 --- a/src/leap/keymanager/tests/test_validation.py +++ b/src/leap/keymanager/tests/test_validation.py @@ -339,7 +339,6 @@ X2+l7IOSt+31KQCBFN/VmhTySJOVQC1d2A56lSH2c/DWVClji+x3suzn -----END PGP PUBLIC KEY BLOCK----- """ - -import unittest if __name__ == "__main__": + import unittest unittest.main() -- cgit v1.2.3 From 3fab338ef4e1ae0efcfaee455ae04881aa013083 Mon Sep 17 00:00:00 2001 From: Bruno Wagner Date: Fri, 24 Jul 2015 16:24:13 -0300 Subject: [style] Fixed pep8 warnings Fixed pep8 warnings to prepare the keymanager for CI --- src/leap/keymanager/__init__.py | 1 + src/leap/keymanager/_version.py | 19 ++++++++----------- src/leap/keymanager/openpgp.py | 7 +++++-- src/leap/keymanager/tests/test_validation.py | 1 + 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 282ff48..999b53c 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -19,6 +19,7 @@ Key Manager is a Nicknym agent for LEAP client. """ # let's do a little sanity check to see if we're using the wrong gnupg import sys +from ._version import get_versions try: from gnupg.gnupg import GPGUtilities diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 28fca96..5153a9b 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -1,5 +1,3 @@ - -IN_LONG_VERSION_PY = True # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (build by setup.py sdist) and build @@ -10,12 +8,15 @@ IN_LONG_VERSION_PY = True # versioneer-0.7+ (https://github.com/warner/python-versioneer) # these strings will be replaced by git during git-archive -git_refnames = "$Format:%d$" -git_full = "$Format:%H$" - - import subprocess import sys +import re +import os.path + +IN_LONG_VERSION_PY = True + +git_refnames = "$Format:%d$" +git_full = "$Format:%H$" def run_command(args, cwd=None, verbose=False): @@ -38,10 +39,6 @@ def run_command(args, cwd=None, verbose=False): return stdout -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 @@ -86,7 +83,7 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False): # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: - print("discarding '%s', no digits" % ",".join(refs-tags)) + print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 794a0ec..5d91dc9 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -114,8 +114,11 @@ class TempGPGWrapper(object): publkeys = filter( lambda pubkey: pubkey.key_id not in privids, publkeys) - listkeys = lambda: self._gpg.list_keys() - listsecretkeys = lambda: self._gpg.list_keys(secret=True) + def listkeys(): + return self._gpg.list_keys() + + def listsecretkeys(): + return self._gpg.list_keys(secret=True) self._gpg = GPG(binary=self._gpgbinary, homedir=tempfile.mkdtemp()) diff --git a/src/leap/keymanager/tests/test_validation.py b/src/leap/keymanager/tests/test_validation.py index 561ca50..ddf1170 100644 --- a/src/leap/keymanager/tests/test_validation.py +++ b/src/leap/keymanager/tests/test_validation.py @@ -18,6 +18,7 @@ Tests for the Validation Levels """ +import unittest from datetime import datetime from twisted.internet.defer import inlineCallbacks -- cgit v1.2.3 From d12f883eed4a8205440e8a4422605be1a1cfe914 Mon Sep 17 00:00:00 2001 From: Bruno Wagner Date: Mon, 3 Aug 2015 17:37:09 -0300 Subject: [style] Re-added lambdas to openpgp on keymanager --- src/leap/keymanager/openpgp.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 5d91dc9..bbdedb2 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -111,14 +111,10 @@ class TempGPGWrapper(object): # and we want to count the keys afterwards. privids = map(lambda privkey: privkey.key_id, privkeys) - publkeys = filter( - lambda pubkey: pubkey.key_id not in privids, publkeys) + publkeys = filter(lambda pubkey: pubkey.key_id not in privids, publkeys) - def listkeys(): - return self._gpg.list_keys() - - def listsecretkeys(): - return self._gpg.list_keys(secret=True) + listkeys = lambda: self._gpg.list_keys() + listsecretkeys = lambda: self._gpg.list_keys(secret=True) self._gpg = GPG(binary=self._gpgbinary, homedir=tempfile.mkdtemp()) -- cgit v1.2.3 From 711fce95bf8f65c0f5a4eaddb4023eda29bc16ad Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 17 Aug 2015 19:22:14 -0400 Subject: [style] pep8 fix --- src/leap/keymanager/openpgp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index bbdedb2..794a0ec 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -111,7 +111,8 @@ class TempGPGWrapper(object): # and we want to count the keys afterwards. privids = map(lambda privkey: privkey.key_id, privkeys) - publkeys = filter(lambda pubkey: pubkey.key_id not in privids, publkeys) + publkeys = filter( + lambda pubkey: pubkey.key_id not in privids, publkeys) listkeys = lambda: self._gpg.list_keys() listsecretkeys = lambda: self._gpg.list_keys(secret=True) -- cgit v1.2.3 From 489289783cdd6bc398c52e0d34999f273174f427 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Fri, 28 Aug 2015 11:21:34 -0400 Subject: freeze debian version --- src/leap/keymanager/_version.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index ea862a7..1fc6e7d 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -1,9 +1,13 @@ -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (build by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. -version_version = '0.3.8' -version_full = '0929d3953191e7ad5ec51f3e94ad6d7608428d48' +# This file was generated by the `freeze_debianver` command in setup.py +# Using 'versioneer.py' (0.7+) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. +version_version = '0.4.2' +version_full = 'dc26f67236fc540f17529df35128f49dcd1b42a4' + + +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} -- cgit v1.2.3 From ff15f95460036485a417964c6ed61ebffe7b9e46 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Mon, 14 Sep 2015 23:08:41 -0400 Subject: [feat] use async events api this avoids using a separate thread with tornado ioloop for events client, since we can use twisted reactor. - Resolves: #7274 --- src/leap/keymanager/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 999b53c..34bc964 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -55,7 +55,7 @@ from twisted.internet import defer from urlparse import urlparse from leap.common.check import leap_assert -from leap.common.events import emit, catalog +from leap.common.events import emit_async, catalog from leap.common.decorators import memoized_method from leap.keymanager.errors import ( @@ -287,7 +287,7 @@ class KeyManager(object): self._api_version, self._uid) self._put(uri, data) - emit(catalog.KEYMANAGER_DONE_UPLOADING_KEYS, self._address) + emit_async(catalog.KEYMANAGER_DONE_UPLOADING_KEYS, self._address) d = self.get_key( self._address, ktype, private=False, fetch_remote=False) @@ -323,24 +323,24 @@ class KeyManager(object): leap_assert( ktype in self._wrapper_map, 'Unkown key type: %s.' % str(ktype)) - emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) + emit_async(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) def key_found(key): - emit(catalog.KEYMANAGER_KEY_FOUND, address) + emit_async(catalog.KEYMANAGER_KEY_FOUND, address) return key def key_not_found(failure): if not failure.check(KeyNotFound): return failure - emit(catalog.KEYMANAGER_KEY_NOT_FOUND, address) + emit_async(catalog.KEYMANAGER_KEY_NOT_FOUND, address) # we will only try to fetch a key from nickserver if fetch_remote # is True and the key is not private. if fetch_remote is False or private is True: return failure - emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) + emit_async(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) d = self._fetch_keys_from_server(address) d.addCallback( lambda _: @@ -397,10 +397,10 @@ class KeyManager(object): self._assert_supported_key_type(ktype) def signal_finished(key): - emit(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) + emit_async(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) return key - emit(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address) + emit_async(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address) d = self._wrapper_map[ktype].gen_key(self._address) d.addCallback(signal_finished) return d -- cgit v1.2.3 From 481c5807ae99575d20fd15a96321103cbcfcdfd2 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 16 Sep 2015 12:55:08 -0400 Subject: [style] pep8 fix --- src/leap/keymanager/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 34bc964..c4534e5 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -74,8 +74,6 @@ from leap.keymanager.keys import ( ) from leap.keymanager.openpgp import OpenPGPKey, OpenPGPScheme -from ._version import get_versions - __version__ = get_versions()['version'] del get_versions @@ -397,7 +395,8 @@ class KeyManager(object): self._assert_supported_key_type(ktype) def signal_finished(key): - emit_async(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) + emit_async( + catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) return key emit_async(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address) -- cgit v1.2.3 From 0b9f64faef0ba9c5cf2a9efe485794ef9b999fab Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Wed, 16 Sep 2015 11:04:33 +0200 Subject: [feat] add logging to fetch_key In case of failure of fetch_key will be useful to have some logging telling us wich key is fetching. - Related: #7410 --- src/leap/keymanager/__init__.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index c4534e5..cf43004 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -779,6 +779,7 @@ class KeyManager(object): """ self._assert_supported_key_type(ktype) + logger.info("Fetch key for %s from %s" % (address, uri)) res = self._get(uri) if not res.ok: return defer.fail(KeyNotFound(uri)) -- cgit v1.2.3 From 9546348c3603f390fdd6d5a119414142e9bd02ea Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Fri, 18 Sep 2015 17:03:14 +0200 Subject: [feature] Use ca_bundle when fetching keys by url This is necessary as a fetch by url will talk to remote sites or, for providers with a commercial cert, with a cert that had not been signed with the provider CA. - support lookup of local keys by url for providers with a commercial cert - combine ca_bundle with ca_cert_path if specified - close soledad after each test --- src/leap/keymanager/__init__.py | 42 ++++++++++++++++- src/leap/keymanager/tests/__init__.py | 5 +- src/leap/keymanager/tests/test_keymanager.py | 68 ++++++++++++++++++++++++++-- 3 files changed, 107 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index cf43004..1220402 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -18,7 +18,10 @@ Key Manager is a Nicknym agent for LEAP client. """ # let's do a little sanity check to see if we're using the wrong gnupg +import fileinput import sys +import tempfile +from leap.common import ca_bundle from ._version import get_versions try: @@ -134,12 +137,30 @@ class KeyManager(object): } # the following are used to perform https requests self._fetcher = requests - self._session = self._fetcher.session() + self._combined_ca_bundle = self._create_combined_bundle_file() # # utilities # + def _create_combined_bundle_file(self): + leap_ca_bundle = ca_bundle.where() + + if self._ca_cert_path == leap_ca_bundle: + return self._ca_cert_path # don't merge file with itself + elif self._ca_cert_path is None: + return leap_ca_bundle + + tmp_file = tempfile.NamedTemporaryFile(delete=True) # file is auto deleted when python process ends + + with open(tmp_file.name, 'w') as fout: + fin = fileinput.input(files=(leap_ca_bundle, self._ca_cert_path)) + for line in fin: + fout.write(line) + fin.close() + + return tmp_file.name + def _key_class_from_type(self, ktype): """ Return key class from string representation of key type. @@ -176,6 +197,23 @@ class KeyManager(object): # 'Content-type is not JSON.') return res + def _get_with_combined_ca_bundle(self, uri, data=None): + """ + Send a GET request to C{uri} containing C{data}. + + Instead of using the ca_cert provided on construction time, this version also uses + the default certificates shipped with leap.common + + :param uri: The URI of the request. + :type uri: str + :param data: The body of the request. + :type data: dict, str or file + + :return: The response to the request. + :rtype: requests.Response + """ + return self._fetcher.get(uri, data=data, verify=self._combined_ca_bundle) + def _put(self, uri, data=None): """ Send a PUT request to C{uri} containing C{data}. @@ -780,7 +818,7 @@ class KeyManager(object): self._assert_supported_key_type(ktype) logger.info("Fetch key for %s from %s" % (address, uri)) - res = self._get(uri) + res = self._get_with_combined_ca_bundle(uri) if not res.ok: return defer.fail(KeyNotFound(uri)) diff --git a/src/leap/keymanager/tests/__init__.py b/src/leap/keymanager/tests/__init__.py index 7128d20..6b647a4 100644 --- a/src/leap/keymanager/tests/__init__.py +++ b/src/leap/keymanager/tests/__init__.py @@ -73,11 +73,12 @@ class KeyManagerWithSoledadTestCase(unittest.TestCase, BaseLeapTest): d = km._wrapper_map[OpenPGPKey].deferred_indexes d.addCallback(get_and_delete_keys) d.addCallback(lambda _: self.tearDownEnv()) + d.addCallback(lambda _: self._soledad.close()) return d - def _key_manager(self, user=ADDRESS, url='', token=None): + def _key_manager(self, user=ADDRESS, url='', token=None, ca_cert_path=None): return KeyManager(user, url, self._soledad, token=token, - gpgbinary=self.gpg_binary_path) + gpgbinary=self.gpg_binary_path, ca_cert_path=ca_cert_path) def _find_gpg(self): gpg_path = distutils.spawn.find_executable('gpg') diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index a12cac0..984b037 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -22,7 +22,9 @@ Tests for the Key Manager. from datetime import datetime -from mock import Mock +import tempfile +from leap.common import ca_bundle +from mock import Mock, MagicMock, patch from twisted.internet.defer import inlineCallbacks from twisted.trial import unittest @@ -50,6 +52,7 @@ from leap.keymanager.tests import ( NICKSERVER_URI = "http://leap.se/" +REMOTE_KEY_URL = "http://site.domain/key" class KeyManagerUtilTestCase(unittest.TestCase): @@ -287,7 +290,6 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): content = PUBLIC_KEY km._fetcher.get = Mock(return_value=Response()) - km.ca_cert_path = 'cacertpath' yield km.fetch_key(ADDRESS, "http://site.domain/key", OpenPGPKey) key = yield km.get_key(ADDRESS, OpenPGPKey) @@ -304,7 +306,6 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): content = "" km._fetcher.get = Mock(return_value=Response()) - km.ca_cert_path = 'cacertpath' d = km.fetch_key(ADDRESS, "http://site.domain/key", OpenPGPKey) return self.assertFailure(d, KeyNotFound) @@ -320,10 +321,69 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): content = PUBLIC_KEY km._fetcher.get = Mock(return_value=Response()) - km.ca_cert_path = 'cacertpath' d = km.fetch_key(ADDRESS_2, "http://site.domain/key", OpenPGPKey) return self.assertFailure(d, KeyAddressMismatch) + def _mock_get_response(self, km, body): + class Response(object): + ok = True + content = body + + mock = MagicMock(return_value=Response()) + km._fetcher.get = mock + + return mock + + @inlineCallbacks + def test_fetch_key_uses_ca_bundle_if_none_specified(self): + ca_cert_path = None + km = self._key_manager(ca_cert_path=ca_cert_path) + get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) + + yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) + + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=ca_bundle.where()) + + @inlineCallbacks + def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert_path(self): + ca_cert_path = ca_bundle.where() + km = self._key_manager(ca_cert_path=ca_cert_path) + get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) + + yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) + + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=ca_bundle.where()) + + @inlineCallbacks + def test_fetch_uses_combined_ca_bundle_otherwise(self): + with tempfile.NamedTemporaryFile() as tmp_input, tempfile.NamedTemporaryFile() as tmp_output: + ca_content = 'some\ncontent\n' + ca_cert_path = tmp_input.name + self._dump_to_file(ca_cert_path, ca_content) + + with patch('leap.keymanager.tempfile.NamedTemporaryFile') as mock: + mock.return_value = tmp_output + km = self._key_manager(ca_cert_path=ca_cert_path) + get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) + + yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) + + # assert that combined bundle file is passed to get call + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=tmp_output.name) + + # assert that files got appended + expected = self._slurp_file(ca_bundle.where()) + ca_content + self.assertEqual(expected, self._slurp_file(tmp_output.name)) + + def _dump_to_file(self, filename, content): + with open(filename, 'w') as out: + out.write(content) + + def _slurp_file(self, filename): + with open(filename) as f: + content = f.read() + return content + class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): -- cgit v1.2.3 From 3b0e1694bc3280896a845d92f55590b1553c4a3f Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Mon, 21 Sep 2015 19:59:11 +0200 Subject: [style] fix pep8 problems --- src/leap/keymanager/__init__.py | 10 ++++++---- src/leap/keymanager/tests/__init__.py | 6 ++++-- src/leap/keymanager/tests/test_keymanager.py | 14 +++++++++----- 3 files changed, 19 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 1220402..5248cb0 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -151,7 +151,8 @@ class KeyManager(object): elif self._ca_cert_path is None: return leap_ca_bundle - tmp_file = tempfile.NamedTemporaryFile(delete=True) # file is auto deleted when python process ends + # file is auto deleted when python process ends + tmp_file = tempfile.NamedTemporaryFile(delete=True) with open(tmp_file.name, 'w') as fout: fin = fileinput.input(files=(leap_ca_bundle, self._ca_cert_path)) @@ -201,8 +202,8 @@ class KeyManager(object): """ Send a GET request to C{uri} containing C{data}. - Instead of using the ca_cert provided on construction time, this version also uses - the default certificates shipped with leap.common + Instead of using the ca_cert provided on construction time, this + version also uses the default certificates shipped with leap.common :param uri: The URI of the request. :type uri: str @@ -212,7 +213,8 @@ class KeyManager(object): :return: The response to the request. :rtype: requests.Response """ - return self._fetcher.get(uri, data=data, verify=self._combined_ca_bundle) + return self._fetcher.get( + uri, data=data, verify=self._combined_ca_bundle) def _put(self, uri, data=None): """ diff --git a/src/leap/keymanager/tests/__init__.py b/src/leap/keymanager/tests/__init__.py index 6b647a4..9b95e1a 100644 --- a/src/leap/keymanager/tests/__init__.py +++ b/src/leap/keymanager/tests/__init__.py @@ -76,9 +76,11 @@ class KeyManagerWithSoledadTestCase(unittest.TestCase, BaseLeapTest): d.addCallback(lambda _: self._soledad.close()) return d - def _key_manager(self, user=ADDRESS, url='', token=None, ca_cert_path=None): + def _key_manager(self, user=ADDRESS, url='', token=None, + ca_cert_path=None): return KeyManager(user, url, self._soledad, token=token, - gpgbinary=self.gpg_binary_path, ca_cert_path=ca_cert_path) + gpgbinary=self.gpg_binary_path, + ca_cert_path=ca_cert_path) def _find_gpg(self): gpg_path = distutils.spawn.find_executable('gpg') diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 984b037..7c00292 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -342,21 +342,24 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) - get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=ca_bundle.where()) + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, + verify=ca_bundle.where()) @inlineCallbacks - def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert_path(self): + def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert(self): ca_cert_path = ca_bundle.where() km = self._key_manager(ca_cert_path=ca_cert_path) get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) - get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=ca_bundle.where()) + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, + verify=ca_bundle.where()) @inlineCallbacks def test_fetch_uses_combined_ca_bundle_otherwise(self): - with tempfile.NamedTemporaryFile() as tmp_input, tempfile.NamedTemporaryFile() as tmp_output: + with tempfile.NamedTemporaryFile() as tmp_input, \ + tempfile.NamedTemporaryFile() as tmp_output: ca_content = 'some\ncontent\n' ca_cert_path = tmp_input.name self._dump_to_file(ca_cert_path, ca_content) @@ -369,7 +372,8 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) # assert that combined bundle file is passed to get call - get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, verify=tmp_output.name) + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, + verify=tmp_output.name) # assert that files got appended expected = self._slurp_file(ca_bundle.where()) + ca_content -- cgit v1.2.3 From 6d823d4e94e70d19a31894f973754ff05d557493 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Mon, 21 Sep 2015 23:15:33 +0200 Subject: [feat] more verbosity in get_key wrong address log --- src/leap/keymanager/openpgp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 794a0ec..b8b47d0 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -321,7 +321,9 @@ class OpenPGPScheme(EncryptionScheme): raise errors.KeyNotFound(address) leap_assert( address in doc.content[KEY_ADDRESS_KEY], - 'Wrong address in key data.') + 'Wrong address in key %s. Expected %s, found %s.' + % (doc.content[KEY_ID_KEY], address, + doc.content[KEY_ADDRESS_KEY])) key = build_key_from_dict(OpenPGPKey, doc.content) key._gpgbinary = self._gpgbinary return key -- cgit v1.2.3 From 1b805754f1d6efe9af25dcf0ab60b3aa2100ee20 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Tue, 22 Sep 2015 16:18:36 +0200 Subject: [bug] catch request exceptions On fetch_key we were not catching the request exceptions, now they are returned as failure in the deferred as it should. - Related: #7410 --- src/leap/keymanager/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 5248cb0..e378c91 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -820,7 +820,11 @@ class KeyManager(object): self._assert_supported_key_type(ktype) logger.info("Fetch key for %s from %s" % (address, uri)) - res = self._get_with_combined_ca_bundle(uri) + try: + res = self._get_with_combined_ca_bundle(uri) + except Exception as e: + logger.warning("There was a problem fetching key: %s" % (e,)) + return defer.fail(KeyNotFound(uri)) if not res.ok: return defer.fail(KeyNotFound(uri)) -- cgit v1.2.3 From 3da04e10ce961e2606ce00125d092d9daa621636 Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Tue, 22 Sep 2015 17:43:29 +0200 Subject: [bug] treat empty string ca_cert_path as None Fixup for 9546348c36. This problem only occurs in test setups where '' is passed to ca_cert_path. --- src/leap/keymanager/__init__.py | 2 +- src/leap/keymanager/tests/test_keymanager.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index e378c91..cf099bb 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -148,7 +148,7 @@ class KeyManager(object): if self._ca_cert_path == leap_ca_bundle: return self._ca_cert_path # don't merge file with itself - elif self._ca_cert_path is None: + elif not self._ca_cert_path: return leap_ca_bundle # file is auto deleted when python process ends diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 7c00292..3b4aa0f 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -346,7 +346,18 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): verify=ca_bundle.where()) @inlineCallbacks - def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert(self): + def test_fetch_key_uses_ca_bundle_if_empty_string_specified(self): + ca_cert_path = '' + km = self._key_manager(ca_cert_path=ca_cert_path) + get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) + + yield km.fetch_key(ADDRESS_OTHER, REMOTE_KEY_URL, OpenPGPKey) + + get_mock.assert_called_once_with(REMOTE_KEY_URL, data=None, + verify=ca_bundle.where()) + + @inlineCallbacks + def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert_path(self): ca_cert_path = ca_bundle.where() km = self._key_manager(ca_cert_path=ca_cert_path) get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) -- cgit v1.2.3 From 7242d003877ef08cb7fa0e55a05c915a03b602ab Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Thu, 24 Sep 2015 01:15:11 +0200 Subject: [bug] don't repush a public key with different address During decryption the signing public key was getting repush with a different address as part of the verify usage flagging. - Resolves: https://github.com/pixelated/pixelated-user-agent/issues/466 - Related: #7420 --- src/leap/keymanager/__init__.py | 20 ++++++++++++-------- src/leap/keymanager/tests/test_validation.py | 26 +++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index cf099bb..22fb725 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -590,10 +590,12 @@ class KeyManager(object): if pubkey is None: signature = KeyNotFound(verify) elif signed: - pubkey.sign_used = True - d = self._wrapper_map[ktype].put_key(pubkey, address) - d.addCallback(lambda _: (decrypted, pubkey)) - return d + signature = pubkey + if not pubkey.sign_used: + pubkey.sign_used = True + d = self._wrapper_map[ktype].put_key(pubkey, verify) + d.addCallback(lambda _: (decrypted, signature)) + return d else: signature = InvalidSignature( 'Failed to verify signature with key %s' % @@ -685,10 +687,12 @@ class KeyManager(object): signed = self._wrapper_map[ktype].verify( data, pubkey, detached_sig=detached_sig) if signed: - pubkey.sign_used = True - d = self._wrapper_map[ktype].put_key(pubkey, address) - d.addCallback(lambda _: pubkey) - return d + if not pubkey.sign_used: + pubkey.sign_used = True + d = self._wrapper_map[ktype].put_key(pubkey, address) + d.addCallback(lambda _: pubkey) + return d + return pubkey else: raise InvalidSignature( 'Failed to verify signature with key %s' % diff --git a/src/leap/keymanager/tests/test_validation.py b/src/leap/keymanager/tests/test_validation.py index ddf1170..bcf41c4 100644 --- a/src/leap/keymanager/tests/test_validation.py +++ b/src/leap/keymanager/tests/test_validation.py @@ -30,6 +30,9 @@ from leap.keymanager.tests import ( KeyManagerWithSoledadTestCase, ADDRESS, PUBLIC_KEY, + ADDRESS_2, + PUBLIC_KEY_2, + PRIVATE_KEY_2, KEY_FINGERPRINT ) from leap.keymanager.validation import ValidationLevels @@ -101,7 +104,7 @@ class ValidationLevelsTestCase(KeyManagerWithSoledadTestCase): self.assertEqual(key.fingerprint, UNRELATED_FINGERPRINT) @inlineCallbacks - def test_used(self): + def test_used_with_verify(self): TEXT = "some text" km = self._key_manager() @@ -118,6 +121,27 @@ class ValidationLevelsTestCase(KeyManagerWithSoledadTestCase): validation=ValidationLevels.Provider_Endorsement) yield self.assertFailure(d, KeyNotValidUpgrade) + @inlineCallbacks + def test_used_with_decrypt(self): + TEXT = "some text" + + km = self._key_manager() + yield km.put_raw_key(UNEXPIRED_KEY, OpenPGPKey, ADDRESS) + yield km.put_raw_key(PRIVATE_KEY_2, OpenPGPKey, ADDRESS_2) + yield km.encrypt(TEXT, ADDRESS, OpenPGPKey) + + km2 = self._key_manager() + yield km2.put_raw_key(UNEXPIRED_PRIVATE, OpenPGPKey, ADDRESS) + yield km2.put_raw_key(PUBLIC_KEY_2, OpenPGPKey, ADDRESS_2) + encrypted = yield km2.encrypt(TEXT, ADDRESS_2, OpenPGPKey, + sign=ADDRESS) + + yield km.decrypt(encrypted, ADDRESS_2, OpenPGPKey, verify=ADDRESS) + d = km.put_raw_key( + UNRELATED_KEY, OpenPGPKey, ADDRESS, + validation=ValidationLevels.Provider_Endorsement) + yield self.assertFailure(d, KeyNotValidUpgrade) + @inlineCallbacks def test_signed_key(self): km = self._key_manager() -- cgit v1.2.3 From 4e82d6ef4dc5e3bb311bf5b80b1e92d67cb0f346 Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Thu, 24 Sep 2015 11:46:14 +0200 Subject: [tests] Add regression tests for sign_used Fails if wrong address is passed to the put_key method, or wrong key is marked as sign_used. - Related: #7420 --- src/leap/keymanager/tests/test_keymanager.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src') diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 3b4aa0f..7b90ae1 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -399,6 +399,39 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): content = f.read() return content + @inlineCallbacks + def test_decrypt_updates_sign_used_for_signer(self): + # given + km = self._key_manager() + yield km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY, ADDRESS) + yield km._wrapper_map[OpenPGPKey].put_ascii_key( + PRIVATE_KEY_2, ADDRESS_2) + encdata = yield km.encrypt('data', ADDRESS, OpenPGPKey, + sign=ADDRESS_2, fetch_remote=False) + yield km.decrypt(encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) + + # when + key = yield km.get_key(ADDRESS_2, OpenPGPKey, fetch_remote=False) + + # then + self.assertEqual(True, key.sign_used) + + @inlineCallbacks + def test_decrypt_does_not_update_sign_used_for_recipient(self): + # given + km = self._key_manager() + yield km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY, ADDRESS) + yield km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY_2, ADDRESS_2) + encdata = yield km.encrypt('data', ADDRESS, OpenPGPKey, + sign=ADDRESS_2, fetch_remote=False) + yield km.decrypt(encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) + + # when + key = yield km.get_key(ADDRESS, OpenPGPKey, private=False, fetch_remote=False) + + # then + self.assertEqual(False, key.sign_used) + class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): -- cgit v1.2.3 From 4a090d6e405415607f9c811a7961f8dc0cdd2af0 Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Mon, 21 Sep 2015 15:59:53 +0200 Subject: [bug] keep combined file longer in scope In previous commit 9546348c, the combined bundle ca was not long enough in scope and was therefore deleted when it actually was used. Adopted test to check whether file is deleted. --- src/leap/keymanager/__init__.py | 16 ++++++++++++++-- src/leap/keymanager/tests/test_keymanager.py | 8 +++++--- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 22fb725..f00e049 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -19,6 +19,7 @@ Key Manager is a Nicknym agent for LEAP client. """ # let's do a little sanity check to see if we're using the wrong gnupg import fileinput +import os import sys import tempfile from leap.common import ca_bundle @@ -139,6 +140,18 @@ class KeyManager(object): self._fetcher = requests self._combined_ca_bundle = self._create_combined_bundle_file() + # + # destructor + # + + def __del__(self): + try: + created_tmp_combined_ca_bundle = self._combined_ca_bundle not in [ca_bundle.where(), self._ca_cert_path] + if created_tmp_combined_ca_bundle: + os.remove(self._combined_ca_bundle) + except OSError: + pass + # # utilities # @@ -151,8 +164,7 @@ class KeyManager(object): elif not self._ca_cert_path: return leap_ca_bundle - # file is auto deleted when python process ends - tmp_file = tempfile.NamedTemporaryFile(delete=True) + tmp_file = tempfile.NamedTemporaryFile(delete=False) # delete when keymanager expires with open(tmp_file.name, 'w') as fout: fin = fileinput.input(files=(leap_ca_bundle, self._ca_cert_path)) diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 7b90ae1..b2722b2 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -20,7 +20,7 @@ Tests for the Key Manager. """ - +from os import path from datetime import datetime import tempfile from leap.common import ca_bundle @@ -369,8 +369,7 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): @inlineCallbacks def test_fetch_uses_combined_ca_bundle_otherwise(self): - with tempfile.NamedTemporaryFile() as tmp_input, \ - tempfile.NamedTemporaryFile() as tmp_output: + with tempfile.NamedTemporaryFile() as tmp_input, tempfile.NamedTemporaryFile(delete=False) as tmp_output: ca_content = 'some\ncontent\n' ca_cert_path = tmp_input.name self._dump_to_file(ca_cert_path, ca_content) @@ -390,6 +389,9 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): expected = self._slurp_file(ca_bundle.where()) + ca_content self.assertEqual(expected, self._slurp_file(tmp_output.name)) + del km # force km out of scope + self.assertFalse(path.exists(tmp_output.name)) + def _dump_to_file(self, filename, content): with open(filename, 'w') as out: out.write(content) -- cgit v1.2.3 From 7fa74c8f099fa8e6fedd95ce8a203b46fa9186c5 Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Thu, 24 Sep 2015 14:04:43 +0200 Subject: [style] fix pep8 warnings --- src/leap/keymanager/__init__.py | 7 +++++-- src/leap/keymanager/tests/test_keymanager.py | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index f00e049..01f3b6e 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -22,7 +22,9 @@ import fileinput import os import sys import tempfile + from leap.common import ca_bundle + from ._version import get_versions try: @@ -146,7 +148,8 @@ class KeyManager(object): def __del__(self): try: - created_tmp_combined_ca_bundle = self._combined_ca_bundle not in [ca_bundle.where(), self._ca_cert_path] + created_tmp_combined_ca_bundle = self._combined_ca_bundle not in \ + [ca_bundle.where(), self._ca_cert_path] if created_tmp_combined_ca_bundle: os.remove(self._combined_ca_bundle) except OSError: @@ -164,7 +167,7 @@ class KeyManager(object): elif not self._ca_cert_path: return leap_ca_bundle - tmp_file = tempfile.NamedTemporaryFile(delete=False) # delete when keymanager expires + tmp_file = tempfile.NamedTemporaryFile(delete=False) with open(tmp_file.name, 'w') as fout: fin = fileinput.input(files=(leap_ca_bundle, self._ca_cert_path)) diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index b2722b2..8d4c5da 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -357,7 +357,7 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): verify=ca_bundle.where()) @inlineCallbacks - def test_fetch_key_uses_default_ca_bundle_if_also_set_as_ca_cert_path(self): + def test_fetch_key_use_default_ca_bundle_if_set_as_ca_cert_path(self): ca_cert_path = ca_bundle.where() km = self._key_manager(ca_cert_path=ca_cert_path) get_mock = self._mock_get_response(km, PUBLIC_KEY_OTHER) @@ -369,7 +369,8 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): @inlineCallbacks def test_fetch_uses_combined_ca_bundle_otherwise(self): - with tempfile.NamedTemporaryFile() as tmp_input, tempfile.NamedTemporaryFile(delete=False) as tmp_output: + with tempfile.NamedTemporaryFile() as tmp_input, \ + tempfile.NamedTemporaryFile(delete=False) as tmp_output: ca_content = 'some\ncontent\n' ca_cert_path = tmp_input.name self._dump_to_file(ca_cert_path, ca_content) -- cgit v1.2.3 From 3a28f215f0fca26387507ec770ee248907014f55 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 24 Sep 2015 12:11:37 -0400 Subject: [style] more pep8 fixes --- src/leap/keymanager/tests/test_keymanager.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 8d4c5da..856d6da 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -411,7 +411,8 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): PRIVATE_KEY_2, ADDRESS_2) encdata = yield km.encrypt('data', ADDRESS, OpenPGPKey, sign=ADDRESS_2, fetch_remote=False) - yield km.decrypt(encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) + yield km.decrypt( + encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) # when key = yield km.get_key(ADDRESS_2, OpenPGPKey, fetch_remote=False) @@ -423,14 +424,18 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): def test_decrypt_does_not_update_sign_used_for_recipient(self): # given km = self._key_manager() - yield km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY, ADDRESS) - yield km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY_2, ADDRESS_2) + yield km._wrapper_map[OpenPGPKey].put_ascii_key( + PRIVATE_KEY, ADDRESS) + yield km._wrapper_map[OpenPGPKey].put_ascii_key( + PRIVATE_KEY_2, ADDRESS_2) encdata = yield km.encrypt('data', ADDRESS, OpenPGPKey, sign=ADDRESS_2, fetch_remote=False) - yield km.decrypt(encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) + yield km.decrypt( + encdata, ADDRESS, OpenPGPKey, verify=ADDRESS_2, fetch_remote=False) # when - key = yield km.get_key(ADDRESS, OpenPGPKey, private=False, fetch_remote=False) + key = yield km.get_key( + ADDRESS, OpenPGPKey, private=False, fetch_remote=False) # then self.assertEqual(False, key.sign_used) -- cgit v1.2.3 From cce42536ac2c7588a9df2f6e012bb8991f8bbd75 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 10 Sep 2015 10:36:53 -0400 Subject: [refactor] refactor key parsing so that it can be tested without needing to instantiate the whole OpenPGPScheme object, that receives a soledad instance. --- src/leap/keymanager/openpgp.py | 130 +++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index b8b47d0..069a78e 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # openpgp.py -# Copyright (C) 2013 LEAP +# Copyright (C) 2013-2015 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 @@ -251,7 +251,7 @@ class OpenPGPScheme(EncryptionScheme): leap_assert(is_address(address), 'Not an user address: %s' % address) def _gen_key(_): - with self._temporary_gpgwrapper() as gpg: + with TempGPGWrapper(gpgbinary=self._gpgbinary) as gpg: # TODO: inspect result, or use decorator params = gpg.gen_key_input( key_type='RSA', @@ -348,37 +348,25 @@ class OpenPGPScheme(EncryptionScheme): # TODO: add more checks for correct key data. leap_assert(key_data is not None, 'Data does not represent a key.') - with self._temporary_gpgwrapper() as gpg: - # TODO: inspect result, or use decorator - gpg.import_keys(key_data) - privkey = None - pubkey = None + priv_info, privkey = process_ascii_key( + key_data, self._gpgbinary, secret=True) + pub_info, pubkey = process_ascii_key( + key_data, self._gpgbinary, secret=False) - try: - privkey = gpg.list_keys(secret=True).pop() - except IndexError: - pass - try: - pubkey = gpg.list_keys(secret=False).pop() # unitary keyring - except IndexError: - return (None, None) - - openpgp_privkey = None - if privkey is not None: - # build private key - openpgp_privkey = self._build_key_from_gpg( - privkey, - gpg.export_keys(privkey['fingerprint'], secret=True)) - leap_check(pubkey['fingerprint'] == privkey['fingerprint'], - 'Fingerprints for public and private key differ.', - errors.KeyFingerprintMismatch) - - # build public key - openpgp_pubkey = self._build_key_from_gpg( - pubkey, - gpg.export_keys(pubkey['fingerprint'], secret=False)) - - return (openpgp_pubkey, openpgp_privkey) + if not pubkey: + return (None, None) + + openpgp_privkey = None + if privkey: + # build private key + openpgp_privkey = self._build_key_from_gpg(priv_info, privkey) + leap_check(pub_info['fingerprint'] == priv_info['fingerprint'], + 'Fingerprints for public and private key differ.', + errors.KeyFingerprintMismatch) + # build public key + openpgp_pubkey = self._build_key_from_gpg(pub_info, pubkey) + + return (openpgp_pubkey, openpgp_privkey) def put_ascii_key(self, key_data, address): """ @@ -439,7 +427,7 @@ class OpenPGPScheme(EncryptionScheme): oldkey = build_key_from_dict(OpenPGPKey, doc.content) if key.fingerprint == oldkey.fingerprint: # in case of an update of the key merge them with gnupg - with self._temporary_gpgwrapper() as gpg: + with TempGPGWrapper(gpgbinary=self._gpgbinary) as gpg: gpg.import_keys(oldkey.key_data) gpg.import_keys(key.key_data) gpgkey = gpg.list_keys(secret=key.private).pop() @@ -577,24 +565,7 @@ class OpenPGPScheme(EncryptionScheme): :return: An instance of the key. :rtype: OpenPGPKey """ - expiry_date = None - if key['expires']: - expiry_date = datetime.fromtimestamp(int(key['expires'])) - address = [] - for uid in key['uids']: - address.append(_parse_address(uid)) - - return OpenPGPKey( - address, - gpgbinary=self._gpgbinary, - key_id=key['keyid'], - fingerprint=key['fingerprint'], - key_data=key_data, - private=True if key['type'] == 'sec' else False, - length=int(key['length']), - expiry_date=expiry_date, - refreshed_at=datetime.now(), - ) + return build_gpg_key(key, key_data, self._gpgbinary) def delete_key(self, key): """ @@ -654,21 +625,6 @@ class OpenPGPScheme(EncryptionScheme): # Data encryption, decryption, signing and verifying # - def _temporary_gpgwrapper(self, keys=None): - """ - Return a gpg wrapper that implements the context manager protocol and - contains C{keys}. - - :param keys: keys to conform the keyring. - :type key: list(OpenPGPKey) - - :return: a TempGPGWrapper instance - :rtype: TempGPGWrapper - """ - # TODO do here checks on key_data - return TempGPGWrapper( - keys=keys, gpgbinary=self._gpgbinary) - @staticmethod def _assert_gpg_result_ok(result): """ @@ -713,7 +669,7 @@ class OpenPGPScheme(EncryptionScheme): leap_assert_type(sign, OpenPGPKey) leap_assert(sign.private is True) keys.append(sign) - with self._temporary_gpgwrapper(keys) as gpg: + with TempGPGWrapper(keys, self._gpgbinary) as gpg: result = gpg.encrypt( data, pubkey.fingerprint, default_key=sign.key_id if sign else None, @@ -755,7 +711,7 @@ class OpenPGPScheme(EncryptionScheme): leap_assert_type(verify, OpenPGPKey) leap_assert(verify.private is False) keys.append(verify) - with self._temporary_gpgwrapper(keys) as gpg: + with TempGPGWrapper(keys, self._gpgbinary) as gpg: try: result = gpg.decrypt( data, passphrase=passphrase, always_trust=True) @@ -783,7 +739,7 @@ class OpenPGPScheme(EncryptionScheme): :return: Whether C{data} was encrypted using this wrapper. :rtype: bool """ - with self._temporary_gpgwrapper() as gpg: + with TempGPGWrapper(gpgbinary=self._gpgbinary) as gpg: gpgutil = GPGUtilities(gpg) return gpgutil.is_encrypted_asym(data) @@ -814,7 +770,7 @@ class OpenPGPScheme(EncryptionScheme): # result.fingerprint - contains the fingerprint of the key used to # sign. - with self._temporary_gpgwrapper(privkey) as gpg: + with TempGPGWrapper(privkey, self._gpgbinary) as gpg: result = gpg.sign(data, default_key=privkey.key_id, digest_algo=digest_algo, clearsign=clearsign, detach=detach, binary=binary) @@ -849,7 +805,7 @@ class OpenPGPScheme(EncryptionScheme): """ leap_assert_type(pubkey, OpenPGPKey) leap_assert(pubkey.private is False) - with self._temporary_gpgwrapper(pubkey) as gpg: + with TempGPGWrapper(pubkey, self._gpgbinary) as gpg: result = None if detached_sig is None: result = gpg.verify(data) @@ -867,3 +823,35 @@ class OpenPGPScheme(EncryptionScheme): rfprint = result.fingerprint kfprint = gpgpubkey['fingerprint'] return valid and rfprint == kfprint + + +def process_ascii_key(key_data, gpgbinary, secret=False): + with TempGPGWrapper(gpgbinary=gpgbinary) as gpg: + try: + gpg.import_keys(key_data) + info = gpg.list_keys(secret=secret).pop() + key = gpg.export_keys(info['fingerprint'], secret=secret) + except IndexError: + info = {} + key = None + return info, key + + +def build_gpg_key(key_info, key_data, gpgbinary=None): + expiry_date = None + if key_info['expires']: + expiry_date = datetime.fromtimestamp(int(key_info['expires'])) + address = [] + for uid in key_info['uids']: + address.append(_parse_address(uid)) + + return OpenPGPKey( + address, + gpgbinary=gpgbinary, + key_id=key_info['keyid'], + fingerprint=key_info['fingerprint'], + key_data=key_data, + private=True if key_info['type'] == 'sec' else False, + length=int(key_info['length']), + expiry_date=expiry_date, + refreshed_at=datetime.now()) -- cgit v1.2.3 From 34573a93a19d1d157a271c4ebdbb76ff5a7d1e63 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 24 Sep 2015 12:44:28 -0400 Subject: [refactor] improve readability Improve readability of operations on generic keys, by assigning the class matching the type of key (_wrapper_map[ktype]) at the beginning of each block. in the future, we could pass the type of key (only PGP keys being used at the moment) on initialization of the Keymanager, so we don't have to pass the ktype on each method call. --- src/leap/keymanager/__init__.py | 48 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 01f3b6e..4826ba7 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -376,6 +376,8 @@ class KeyManager(object): leap_assert( ktype in self._wrapper_map, 'Unkown key type: %s.' % str(ktype)) + _keys = self._wrapper_map[ktype] + emit_async(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) def key_found(key): @@ -396,13 +398,12 @@ class KeyManager(object): emit_async(catalog.KEYMANAGER_LOOKING_FOR_KEY, address) d = self._fetch_keys_from_server(address) d.addCallback( - lambda _: - self._wrapper_map[ktype].get_key(address, private=False)) + lambda _: _keys.get_key(address, private=False)) d.addCallback(key_found) return d # return key if it exists in local database - d = self._wrapper_map[ktype].get_key(address, private=private) + d = _keys.get_key(address, private=private) d.addCallbacks(key_found, key_not_found) return d @@ -448,6 +449,7 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] def signal_finished(key): emit_async( @@ -455,7 +457,8 @@ class KeyManager(object): return key emit_async(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address) - d = self._wrapper_map[ktype].gen_key(self._address) + + d = _keys.gen_key(self._address) d.addCallback(signal_finished) return d @@ -545,14 +548,15 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] def encrypt(keys): pubkey, signkey = keys - encrypted = self._wrapper_map[ktype].encrypt( + encrypted = _keys.encrypt( data, pubkey, passphrase, sign=signkey, cipher_algo=cipher_algo) pubkey.encr_used = True - d = self._wrapper_map[ktype].put_key(pubkey, address) + d = _keys.put_key(pubkey, address) d.addCallback(lambda _: encrypted) return d @@ -597,10 +601,11 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] def decrypt(keys): pubkey, privkey = keys - decrypted, signed = self._wrapper_map[ktype].decrypt( + decrypted, signed = _keys.decrypt( data, privkey, passphrase=passphrase, verify=pubkey) if pubkey is None: signature = KeyNotFound(verify) @@ -608,7 +613,7 @@ class KeyManager(object): signature = pubkey if not pubkey.sign_used: pubkey.sign_used = True - d = self._wrapper_map[ktype].put_key(pubkey, verify) + d = _keys.put_key(pubkey, verify) d.addCallback(lambda _: (decrypted, signature)) return d else: @@ -659,9 +664,10 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] def sign(privkey): - return self._wrapper_map[ktype].sign( + return _keys.sign( data, privkey, digest_algo=digest_algo, clearsign=clearsign, detach=detach, binary=binary) @@ -697,14 +703,15 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] def verify(pubkey): - signed = self._wrapper_map[ktype].verify( + signed = _keys.verify( data, pubkey, detached_sig=detached_sig) if signed: if not pubkey.sign_used: pubkey.sign_used = True - d = self._wrapper_map[ktype].put_key(pubkey, address) + d = keys.put_key(pubkey, address) d.addCallback(lambda _: pubkey) return d return pubkey @@ -732,7 +739,8 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(type(key)) - return self._wrapper_map[type(key)].delete_key(key) + _keys = self._wrapper_map[type(key)] + return _keys.delete_key(key) def put_key(self, key, address): """ @@ -752,7 +760,9 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ - self._assert_supported_key_type(type(key)) + ktype = type(key) + self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] if address not in key.address: return defer.fail( @@ -767,14 +777,13 @@ class KeyManager(object): def check_upgrade(old_key): if key.private or can_upgrade(key, old_key): - return self._wrapper_map[type(key)].put_key(key, address) + return _keys.put_key(key, address) else: raise KeyNotValidUpgrade( "Key %s can not be upgraded by new key %s" % (old_key.key_id, key.key_id)) - d = self._wrapper_map[type(key)].get_key(address, - private=key.private) + d = _keys.get_key(address, private=key.private) d.addErrback(old_key_not_found) d.addCallback(check_upgrade) return d @@ -804,7 +813,9 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) - pubkey, privkey = self._wrapper_map[ktype].parse_ascii_key(key) + _keys = self._wrapper_map[ktype] + + pubkey, privkey = _keys.parse_ascii_key(key) pubkey.validation = validation d = self.put_key(pubkey, address) if privkey is not None: @@ -837,6 +848,7 @@ class KeyManager(object): :raise UnsupportedKeyTypeError: if invalid key type """ self._assert_supported_key_type(ktype) + _keys = self._wrapper_map[ktype] logger.info("Fetch key for %s from %s" % (address, uri)) try: @@ -848,7 +860,7 @@ class KeyManager(object): return defer.fail(KeyNotFound(uri)) # XXX parse binary keys - pubkey, _ = self._wrapper_map[ktype].parse_ascii_key(res.content) + pubkey, _ = _keys.parse_ascii_key(res.content) if pubkey is None: return defer.fail(KeyNotFound(uri)) -- cgit v1.2.3 From 6a8cd66c656b810fb5052c75fa21002de5330273 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Mon, 28 Sep 2015 19:06:20 +0200 Subject: [bug] fix verify keys usage The latests refactor missed one line. --- src/leap/keymanager/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 4826ba7..c7886e0 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -711,7 +711,7 @@ class KeyManager(object): if signed: if not pubkey.sign_used: pubkey.sign_used = True - d = keys.put_key(pubkey, address) + d = _keys.put_key(pubkey, address) d.addCallback(lambda _: pubkey) return d return pubkey -- cgit v1.2.3 From 9a9c53eea49092e80737c84a2f850dd682c33ae3 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Tue, 29 Sep 2015 16:36:20 +0200 Subject: [feat] self-repair the keyring if keys get duplicated In some cases in the past keys got stored twice in different documents. Hopefully this issue is solved now, this tries to self-repair the keyring if encounters that. This is not really solving the problem, if it keeps happening we need to investigate the source. - Resolves: #7498 --- src/leap/keymanager/openpgp.py | 143 +++++++++++++++++++----------- src/leap/keymanager/tests/__init__.py | 7 ++ src/leap/keymanager/tests/test_openpgp.py | 104 +++++++++++++++++++++- 3 files changed, 203 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 069a78e..d648137 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -22,6 +22,7 @@ import os import re import shutil import tempfile +import traceback import io @@ -41,6 +42,8 @@ from leap.keymanager.keys import ( TYPE_ADDRESS_PRIVATE_INDEX, KEY_ADDRESS_KEY, KEY_ID_KEY, + KEY_FINGERPRINT_KEY, + KEY_REFRESHED_AT_KEY, KEYMANAGER_ACTIVE_TYPE, ) @@ -422,41 +425,42 @@ class OpenPGPScheme(EncryptionScheme): :rtype: Deferred """ def check_and_put(docs, key): - if len(docs) == 1: - doc = docs.pop() - oldkey = build_key_from_dict(OpenPGPKey, doc.content) - if key.fingerprint == oldkey.fingerprint: - # in case of an update of the key merge them with gnupg - with TempGPGWrapper(gpgbinary=self._gpgbinary) as gpg: - gpg.import_keys(oldkey.key_data) - gpg.import_keys(key.key_data) - gpgkey = gpg.list_keys(secret=key.private).pop() - mergedkey = self._build_key_from_gpg( - gpgkey, - gpg.export_keys(gpgkey['fingerprint'], - secret=key.private)) - mergedkey.validation = max( - [key.validation, oldkey.validation]) - mergedkey.last_audited_at = oldkey.last_audited_at - mergedkey.refreshed_at = key.refreshed_at - mergedkey.encr_used = key.encr_used or oldkey.encr_used - mergedkey.sign_used = key.sign_used or oldkey.sign_used - doc.set_json(mergedkey.get_json()) - d = self._soledad.put_doc(doc) - else: - logger.critical( - "Can't put a key whith the same key_id and different " - "fingerprint: %s, %s" - % (key.fingerprint, oldkey.fingerprint)) - d = defer.fail( - errors.KeyFingerprintMismatch(key.fingerprint)) + deferred_repair = defer.succeed(None) + if len(docs) == 0: + return self._soledad.create_doc_from_json(key.get_json()) elif len(docs) > 1: + deferred_repair = self._repair_key_docs(docs, key.key_id) + + doc = docs[0] + oldkey = build_key_from_dict(OpenPGPKey, doc.content) + if key.fingerprint != oldkey.fingerprint: logger.critical( - "There is more than one key with the same key_id %s" - % (key.key_id,)) - d = defer.fail(errors.KeyAttributesDiffer(key.key_id)) - else: - d = self._soledad.create_doc_from_json(key.get_json()) + "Can't put a key whith the same key_id and different " + "fingerprint: %s, %s" + % (key.fingerprint, oldkey.fingerprint)) + return defer.fail( + errors.KeyFingerprintMismatch(key.fingerprint)) + + # in case of an update of the key merge them with gnupg + with TempGPGWrapper(gpgbinary=self._gpgbinary) as gpg: + gpg.import_keys(oldkey.key_data) + gpg.import_keys(key.key_data) + gpgkey = gpg.list_keys(secret=key.private).pop() + mergedkey = self._build_key_from_gpg( + gpgkey, + gpg.export_keys(gpgkey['fingerprint'], + secret=key.private)) + mergedkey.validation = max( + [key.validation, oldkey.validation]) + mergedkey.last_audited_at = oldkey.last_audited_at + mergedkey.refreshed_at = key.refreshed_at + mergedkey.encr_used = key.encr_used or oldkey.encr_used + mergedkey.sign_used = key.sign_used or oldkey.sign_used + doc.set_json(mergedkey.get_json()) + deferred_put = self._soledad.put_doc(doc) + + d = defer.gatherResults([deferred_put, deferred_repair]) + d.addCallback(lambda res: res[0]) return d d = self._soledad.get_from_index( @@ -533,14 +537,21 @@ class OpenPGPScheme(EncryptionScheme): self.KEY_TYPE, key_id, '1' if private else '0') - d.addCallback(get_doc, key_id) + d.addCallback(get_doc, key_id, activedoc) return d - def get_doc(doclist, key_id): - leap_assert( - len(doclist) is 1, - 'There is %d keys for id %s!' % (len(doclist), key_id)) - return doclist.pop() + def get_doc(doclist, key_id, activedoc): + if len(doclist) == 0: + logger.warning('There is no key for id %s! Self-repairing it.' + % (key_id)) + d = self._soledad.delete_doc(activedoc) + d.addCallback(lambda _: None) + return d + elif len(doclist) > 1: + d = self._repair_key_docs(doclist, key_id) + d.addCallback(lambda _: doclist[0]) + return d + return doclist[0] d = self._soledad.get_from_index( TYPE_ADDRESS_PRIVATE_INDEX, @@ -598,18 +609,20 @@ class OpenPGPScheme(EncryptionScheme): def delete_key(docs): if len(docs) == 0: raise errors.KeyNotFound(key) - if len(docs) > 1: - logger.critical("There is more than one key for key_id %s" - % key.key_id) - - doc = None - for d in docs: - if d.content['fingerprint'] == key.fingerprint: - doc = d - break - if doc is None: + elif len(docs) > 1: + logger.warning("There is more than one key for key_id %s" + % key.key_id) + + has_deleted = False + deferreds = [] + for doc in docs: + if doc.content['fingerprint'] == key.fingerprint: + d = self._soledad.delete_doc(doc) + deferreds.append(d) + has_deleted = True + if not has_deleted: raise errors.KeyNotFound(key) - return self._soledad.delete_doc(doc) + return defer.gatherResults(deferreds) d = self._soledad.get_from_index( TYPE_ID_PRIVATE_INDEX, @@ -621,6 +634,36 @@ class OpenPGPScheme(EncryptionScheme): d.addCallback(delete_key) return d + def _repair_key_docs(self, doclist, key_id): + """ + If there is more than one key for a key id try to self-repair it + + :return: a Deferred that will be fired once all the deletions are + completed + :rtype: Deferred + """ + logger.error("BUG ---------------------------------------------------") + logger.error("There is more than one key with the same key_id %s:" + % (key_id,)) + + def log_key_doc(doc): + logger.error("\t%s: %s" % (doc.content[KEY_ADDRESS_KEY], + doc.content[KEY_FINGERPRINT_KEY])) + + doclist.sort(key=lambda doc: doc.content[KEY_REFRESHED_AT_KEY], + reverse=True) + log_key_doc(doclist[0]) + deferreds = [] + for doc in doclist[1:]: + log_key_doc(doc) + d = self._soledad.delete_doc(doc) + deferreds.append(d) + + logger.error("") + logger.error(traceback.extract_stack()) + logger.error("BUG (please report above info) ------------------------") + return defer.gatherResults(deferreds, consumeErrors=True) + # # Data encryption, decryption, signing and verifying # diff --git a/src/leap/keymanager/tests/__init__.py b/src/leap/keymanager/tests/__init__.py index 9b95e1a..cd612c4 100644 --- a/src/leap/keymanager/tests/__init__.py +++ b/src/leap/keymanager/tests/__init__.py @@ -66,9 +66,15 @@ class KeyManagerWithSoledadTestCase(unittest.TestCase, BaseLeapTest): for private in [True, False]: d = km.get_all_keys(private=private) d.addCallback(delete_keys) + d.addCallback(check_deleted, private) deferreds.append(d) return gatherResults(deferreds) + def check_deleted(_, private): + d = km.get_all_keys(private=private) + d.addCallback(lambda keys: self.assertEqual(keys, [])) + return d + # wait for the indexes to be ready for the tear down d = km._wrapper_map[OpenPGPKey].deferred_indexes d.addCallback(get_and_delete_keys) @@ -91,6 +97,7 @@ class KeyManagerWithSoledadTestCase(unittest.TestCase, BaseLeapTest): # key 24D18DDF: public key "Leap Test Key " +KEY_ID = "2F455E2824D18DDF" KEY_FINGERPRINT = "E36E738D69173C13D709E44F2F455E2824D18DDF" PUBLIC_KEY = """ -----BEGIN PGP PUBLIC KEY BLOCK----- diff --git a/src/leap/keymanager/tests/test_openpgp.py b/src/leap/keymanager/tests/test_openpgp.py index 5f85c74..bae83db 100644 --- a/src/leap/keymanager/tests/test_openpgp.py +++ b/src/leap/keymanager/tests/test_openpgp.py @@ -21,12 +21,15 @@ Tests for the OpenPGP support on Key Manager. """ -from twisted.internet.defer import inlineCallbacks +from datetime import datetime +from mock import Mock +from twisted.internet.defer import inlineCallbacks, gatherResults, succeed from leap.keymanager import ( KeyNotFound, openpgp, ) +from leap.keymanager.keys import TYPE_ID_PRIVATE_INDEX from leap.keymanager.openpgp import OpenPGPKey from leap.keymanager.tests import ( KeyManagerWithSoledadTestCase, @@ -34,6 +37,7 @@ from leap.keymanager.tests import ( ADDRESS_2, KEY_FINGERPRINT, PUBLIC_KEY, + KEY_ID, PUBLIC_KEY_2, PRIVATE_KEY, PRIVATE_KEY_2, @@ -247,6 +251,104 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase): validsign = pgp.verify(data, pubkey, detached_sig=signature) self.assertTrue(validsign) + @inlineCallbacks + def test_self_repair_three_keys(self): + pgp = openpgp.OpenPGPScheme( + self._soledad, gpgbinary=self.gpg_binary_path) + yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS) + + get_from_index = self._soledad.get_from_index + delete_doc = self._soledad.delete_doc + + def my_get_from_index(*args): + if (args[0] == TYPE_ID_PRIVATE_INDEX and + args[2] == KEY_ID): + k1 = OpenPGPKey(ADDRESS, key_id="1", + refreshed_at=datetime(2005, 1, 1)) + k2 = OpenPGPKey(ADDRESS, key_id="2", + refreshed_at=datetime(2007, 1, 1)) + k3 = OpenPGPKey(ADDRESS, key_id="3", + refreshed_at=datetime(2001, 1, 1)) + d1 = self._soledad.create_doc_from_json(k1.get_json()) + d2 = self._soledad.create_doc_from_json(k2.get_json()) + d3 = self._soledad.create_doc_from_json(k3.get_json()) + return gatherResults([d1, d2, d3]) + return get_from_index(*args) + + self._soledad.get_from_index = my_get_from_index + self._soledad.delete_doc = Mock(return_value=succeed(None)) + + key = yield pgp.get_key(ADDRESS, private=False) + + try: + self.assertEqual(key.key_id, "2") + self.assertEqual(self._soledad.delete_doc.call_count, 2) + finally: + self._soledad.get_from_index = get_from_index + self._soledad.delete_doc = delete_doc + + @inlineCallbacks + def test_self_repair_no_keys(self): + pgp = openpgp.OpenPGPScheme( + self._soledad, gpgbinary=self.gpg_binary_path) + yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS) + + get_from_index = self._soledad.get_from_index + delete_doc = self._soledad.delete_doc + + def my_get_from_index(*args): + if (args[0] == TYPE_ID_PRIVATE_INDEX and + args[2] == KEY_ID): + return succeed([]) + return get_from_index(*args) + + self._soledad.get_from_index = my_get_from_index + self._soledad.delete_doc = Mock(return_value=succeed(None)) + + try: + yield self.assertFailure(pgp.get_key(ADDRESS, private=False), + KeyNotFound) + self.assertEqual(self._soledad.delete_doc.call_count, 1) + finally: + self._soledad.get_from_index = get_from_index + self._soledad.delete_doc = delete_doc + + @inlineCallbacks + def test_self_repair_put_keys(self): + pgp = openpgp.OpenPGPScheme( + self._soledad, gpgbinary=self.gpg_binary_path) + + get_from_index = self._soledad.get_from_index + delete_doc = self._soledad.delete_doc + + def my_get_from_index(*args): + if (args[0] == TYPE_ID_PRIVATE_INDEX and + args[2] == KEY_ID): + k1 = OpenPGPKey(ADDRESS, key_id="1", + fingerprint=KEY_FINGERPRINT, + refreshed_at=datetime(2005, 1, 1)) + k2 = OpenPGPKey(ADDRESS, key_id="2", + fingerprint=KEY_FINGERPRINT, + refreshed_at=datetime(2007, 1, 1)) + k3 = OpenPGPKey(ADDRESS, key_id="3", + fingerprint=KEY_FINGERPRINT, + refreshed_at=datetime(2001, 1, 1)) + d1 = self._soledad.create_doc_from_json(k1.get_json()) + d2 = self._soledad.create_doc_from_json(k2.get_json()) + d3 = self._soledad.create_doc_from_json(k3.get_json()) + return gatherResults([d1, d2, d3]) + return get_from_index(*args) + + self._soledad.get_from_index = my_get_from_index + self._soledad.delete_doc = Mock(return_value=succeed(None)) + + try: + yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS) + self.assertEqual(self._soledad.delete_doc.call_count, 2) + finally: + self._soledad.get_from_index = get_from_index + self._soledad.delete_doc = delete_doc + def _assert_key_not_found(self, pgp, address, private=False): d = pgp.get_key(address, private=private) return self.assertFailure(d, KeyNotFound) -- cgit v1.2.3 From 18023cb47380a8e6178b4d3ce8a0958bb1234b77 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 6 Oct 2015 16:01:47 -0400 Subject: freeze debian version (0.4.3b1) --- src/leap/keymanager/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index 1fc6e7d..ea36665 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,8 +5,8 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.4.2' -version_full = 'dc26f67236fc540f17529df35128f49dcd1b42a4' +version_version = '0.4.3b1' +version_full = 'f404e4abc426ce08850283345ce162fb9b5403cf' def get_versions(default={}, verbose=False): -- cgit v1.2.3 From 187da0973203a358eb9d02399edfccaf6373abb4 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 29 Oct 2015 12:02:17 -0400 Subject: freeze debian version --- src/leap/keymanager/_version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/_version.py b/src/leap/keymanager/_version.py index ea36665..049099d 100644 --- a/src/leap/keymanager/_version.py +++ b/src/leap/keymanager/_version.py @@ -5,8 +5,8 @@ # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. -version_version = '0.4.3b1' -version_full = 'f404e4abc426ce08850283345ce162fb9b5403cf' +version_version = '0.4.3' +version_full = 'f17f8c43e217b65a951e5db357699c2d2af6098f' def get_versions(default={}, verbose=False): -- cgit v1.2.3