commit python3-gnupg for openSUSE:Factory
Hello community,
here is the log from the commit of package python3-gnupg for openSUSE:Factory checked in at 2016-09-21 18:48:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-gnupg (Old)
and /work/SRC/openSUSE:Factory/.python3-gnupg.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-gnupg"
Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-gnupg/python3-gnupg.changes 2016-05-25 21:24:18.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-gnupg.new/python3-gnupg.changes 2016-09-21 18:49:00.000000000 +0200
@@ -1,0 +2,19 @@
+Sun Sep 18 15:52:25 UTC 2016 - arun@gmx.de
+
+- update to version 0.3.9:
+ * Fixed #38: You can now request information about signatures
+ against keys. Thanks to SunDwarf for the suggestion and patch,
+ which was used as a basis for this change.
+ * Fixed #49: When exporting keys, no attempt is made to decode the
+ output when armor=False is specified.
+ * Fixed #53: A FAILURE message caused by passing an incorrect
+ passphrase is handled.
+ * Handled EXPORTED and EXPORT_RES messages while exporting
+ keys. Thanks to Marcel Pörner for the patch.
+ * Fixed #54: Improved error message shown when gpg is not available.
+ * Fixed #55: Added support for KEY_CONSIDERED while verifying.
+ * Avoided encoding problems with filenames under Windows. Thanks to
+ Kévin Bernard-Allies for the patch.
+ * Fixed #57: Used a better mechanism for comparing keys.
+
+-------------------------------------------------------------------
@@ -6 +24,0 @@
-
Old:
----
python-gnupg-0.3.8.tar.gz
New:
----
python-gnupg-0.3.9.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python3-gnupg.spec ++++++
--- /var/tmp/diff_new_pack.hS2SdC/_old 2016-09-21 18:49:02.000000000 +0200
+++ /var/tmp/diff_new_pack.hS2SdC/_new 2016-09-21 18:49:02.000000000 +0200
@@ -17,7 +17,7 @@
Name: python3-gnupg
-Version: 0.3.8
+Version: 0.3.9
Release: 0
Url: https://bitbucket.org/vinay.sajip/python-gnupg
Summary: A wrapper for the Gnu Privacy Guard (GPG or GnuPG)
++++++ python-gnupg-0.3.8.tar.gz -> python-gnupg-0.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-gnupg-0.3.8/PKG-INFO new/python-gnupg-0.3.9/PKG-INFO
--- old/python-gnupg-0.3.8/PKG-INFO 2015-09-24 23:03:50.000000000 +0200
+++ new/python-gnupg-0.3.9/PKG-INFO 2016-09-10 09:41:21.000000000 +0200
@@ -1,12 +1,12 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: python-gnupg
-Version: 0.3.8
+Version: 0.3.9
Summary: A wrapper for the Gnu Privacy Guard (GPG or GnuPG)
Home-page: http://packages.python.org/python-gnupg/index.html
Author: Vinay Sajip
Author-email: vinay_sajip@red-dove.com
-License: Copyright (C) 2008-2014 by Vinay Sajip. All Rights Reserved. See LICENSE.txt for license.
-Download-URL: https://pypi.python.org/packages/source/p/python-gnupg/python-gnupg-0.3.8.ta...
+License: Copyright (C) 2008-2016 by Vinay Sajip. All Rights Reserved. See LICENSE.txt for license.
+Download-URL: https://pypi.python.org/packages/source/p/python-gnupg/python-gnupg-0.3.9.ta...
Description: This module allows easy access to GnuPG's key management, encryption and signature functionality from Python programs. It is intended for use with Python 2.4 or greater.
Platform: No particular restrictions
Classifier: Development Status :: 5 - Production/Stable
@@ -23,6 +23,5 @@
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-gnupg-0.3.8/README.rst new/python-gnupg-0.3.9/README.rst
--- old/python-gnupg-0.3.8/README.rst 2015-09-24 19:07:37.000000000 +0200
+++ new/python-gnupg-0.3.9/README.rst 2016-09-10 09:37:53.000000000 +0200
@@ -54,11 +54,39 @@
N.B: GCnn refers to an issue nn on Google Code.
-0.3.9 (future)
+0.4.0 (future)
--------------
Released: Not yet
+0.3.9
+-----
+
+Released: 2016-09-10
+
+* Fixed #38: You can now request information about signatures against
+ keys. Thanks to SunDwarf for the suggestion and patch, which was used
+ as a basis for this change.
+
+* Fixed #49: When exporting keys, no attempt is made to decode the output when
+ armor=False is specified.
+
+* Fixed #53: A ``FAILURE`` message caused by passing an incorrect passphrase
+ is handled.
+
+* Handled ``EXPORTED`` and ``EXPORT_RES`` messages while exporting keys. Thanks
+ to Marcel Pörner for the patch.
+
+* Fixed #54: Improved error message shown when gpg is not available.
+
+* Fixed #55: Added support for ``KEY_CONSIDERED`` while verifying.
+
+* Avoided encoding problems with filenames under Windows. Thanks to Kévin
+ Bernard-Allies for the patch.
+
+* Fixed #57: Used a better mechanism for comparing keys.
+
+
0.3.8
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-gnupg-0.3.8/gnupg.py new/python-gnupg-0.3.9/gnupg.py
--- old/python-gnupg-0.3.8/gnupg.py 2015-09-24 19:03:56.000000000 +0200
+++ new/python-gnupg-0.3.9/gnupg.py 2016-09-10 09:38:35.000000000 +0200
@@ -27,18 +27,18 @@
and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
the previous versions.
-Modifications Copyright (C) 2008-2014 Vinay Sajip. All rights reserved.
+Modifications Copyright (C) 2008-2016 Vinay Sajip. All rights reserved.
A unittest harness (test_gnupg.py) has also been added.
"""
-__version__ = "0.3.8"
+__version__ = "0.3.9"
__author__ = "Vinay Sajip"
-__date__ = "$24-Sep-2015 18:03:55$"
+__date__ = "$10-Sep-2016 08:38:35$"
try:
from io import StringIO
-except ImportError:
+except ImportError: # pragma: no cover
from cStringIO import StringIO
import codecs
@@ -53,7 +53,7 @@
import threading
STARTUPINFO = None
-if os.name == 'nt':
+if os.name == 'nt': # pragma: no cover
try:
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW, SW_HIDE
except ImportError:
@@ -80,7 +80,7 @@
logger.addHandler(NullHandler())
# We use the test below because it works for Jython as well as CPython
-if os.path.__name__ == 'ntpath':
+if os.path.__name__ == 'ntpath': # pragma: no cover
# On Windows, we don't need shell quoting, other than worrying about
# paths with spaces in them.
def shell_quote(s):
@@ -105,7 +105,7 @@
command shells
:rtype: The passed-in type
"""
- if not isinstance(s, string_types):
+ if not isinstance(s, string_types): # pragma: no cover
raise TypeError('Expected string type, got %s' % type(s))
if not s:
result = "''"
@@ -138,7 +138,7 @@
sent = 0
if hasattr(sys.stdin, 'encoding'):
enc = sys.stdin.encoding
- else:
+ else: # pragma: no cover
enc = 'ascii'
while True:
# See issue #39: read can fail when e.g. a text stream is provided
@@ -151,10 +151,10 @@
if not data:
break
sent += len(data)
- logger.debug("sending chunk (%d): %r", sent, data[:256])
+ # logger.debug("sending chunk (%d): %r", sent, data[:256])
try:
outstream.write(data)
- except UnicodeError:
+ except UnicodeError: # pragma: no cover
outstream.write(data.encode(enc))
except:
# Can sometimes get 'broken pipe' errors even when the data has all
@@ -163,7 +163,7 @@
break
try:
outstream.close()
- except IOError:
+ except IOError: # pragma: no cover
logger.warning('Exception occurred while closing: ignored', exc_info=1)
logger.debug("closed output, %d bytes sent", sent)
@@ -187,7 +187,7 @@
try:
from io import BytesIO
rv = BytesIO(s)
- except ImportError:
+ except ImportError: # pragma: no cover
rv = StringIO(s)
return rv
@@ -245,20 +245,21 @@
"DECRYPTION_OKAY", "INV_SGNR", "FILE_START", "FILE_ERROR",
"FILE_DONE", "PKA_TRUST_GOOD", "PKA_TRUST_BAD", "BADMDC",
"GOODMDC", "NO_SGNR", "NOTATION_NAME", "NOTATION_DATA",
- "PROGRESS", "PINENTRY_LAUNCHED", "NEWSIG"):
+ "PROGRESS", "PINENTRY_LAUNCHED", "NEWSIG",
+ "KEY_CONSIDERED"):
pass
- elif key == "BADSIG":
+ elif key == "BADSIG": # pragma: no cover
self.valid = False
self.status = 'signature bad'
self.key_id, self.username = value.split(None, 1)
- elif key == "ERRSIG":
+ elif key == "ERRSIG": # pragma: no cover
self.valid = False
(self.key_id,
algo, hash_algo,
cls,
self.timestamp) = value.split()[:5]
self.status = 'signature error'
- elif key == "EXPSIG":
+ elif key == "EXPSIG": # pragma: no cover
self.valid = False
self.status = 'signature expired'
self.key_id, self.username = value.split(None, 1)
@@ -277,21 +278,21 @@
elif key == "SIG_ID":
(self.signature_id,
self.creation_date, self.timestamp) = value.split()
- elif key == "DECRYPTION_FAILED":
+ elif key == "DECRYPTION_FAILED": # pragma: no cover
self.valid = False
self.key_id = value
self.status = 'decryption failed'
- elif key == "NO_PUBKEY":
+ elif key == "NO_PUBKEY": # pragma: no cover
self.valid = False
self.key_id = value
self.status = 'no public key'
- elif key in ("KEYEXPIRED", "SIGEXPIRED", "KEYREVOKED"):
+ elif key in ("KEYEXPIRED", "SIGEXPIRED", "KEYREVOKED"): # pragma: no cover
# these are useless in verify, since they are spit out for any
# pub/subkeys on the key, not just the one doing the signing.
# if we want to check for signatures with expired key,
# the relevant flag is EXPKEYSIG or REVKEYSIG.
pass
- elif key in ("EXPKEYSIG", "REVKEYSIG"):
+ elif key in ("EXPKEYSIG", "REVKEYSIG"): # pragma: no cover
# signed with expired or revoked key
self.valid = False
self.key_id = value.split()[0]
@@ -300,10 +301,14 @@
else:
self.key_status = 'signing key was revoked'
self.status = self.key_status
- elif key == "UNEXPECTED":
+ elif key in ("UNEXPECTED", "FAILURE"): # pragma: no cover
self.valid = False
self.key_id = value
- self.status = 'unexpected data'
+ if key == "UNEXPECTED":
+ self.status = 'unexpected data'
+ else:
+ # N.B. there might be other reasons
+ self.status = 'incorrect passphrase'
else:
raise ValueError("Unknown status message: %r" % key)
@@ -349,7 +354,7 @@
if key == "IMPORTED":
# this duplicates info we already see in import_ok & import_problem
pass
- elif key == "NODATA":
+ elif key == "NODATA": # pragma: no cover
self.results.append({'fingerprint': None,
'problem': '0', 'text': 'No valid data found'})
elif key == "IMPORT_OK":
@@ -362,7 +367,7 @@
self.results.append({'fingerprint': fingerprint,
'ok': reason, 'text': reasontext})
self.fingerprints.append(fingerprint)
- elif key == "IMPORT_PROBLEM":
+ elif key == "IMPORT_PROBLEM": # pragma: no cover
try:
reason, fingerprint = value.split()
except:
@@ -374,19 +379,19 @@
import_res = value.split()
for i, count in enumerate(self.counts):
setattr(self, count, int(import_res[i]))
- elif key == "KEYEXPIRED":
+ elif key == "KEYEXPIRED": # pragma: no cover
self.results.append({'fingerprint': None,
'problem': '0', 'text': 'Key expired'})
- elif key == "SIGEXPIRED":
+ elif key == "SIGEXPIRED": # pragma: no cover
self.results.append({'fingerprint': None,
'problem': '0', 'text': 'Signature expired'})
- else:
+ else: # pragma: no cover
raise ValueError("Unknown status message: %r" % key)
def summary(self):
l = []
l.append('%d imported' % self.imported)
- if self.not_imported:
+ if self.not_imported: # pragma: no cover
l.append('%d not imported' % self.not_imported)
return ', '.join(l)
@@ -429,6 +434,7 @@
for i, var in enumerate(self.FIELDS):
result[var] = args[i]
result['uids'] = []
+ result['sigs'] = []
return result
def pub(self, args):
@@ -443,11 +449,11 @@
self.curkey['uids'].append(uid)
self.uids.append(uid)
- def handle_status(self, key, value):
+ def handle_status(self, key, value): # pragma: no cover
pass
class ListKeys(SearchKeys):
- ''' Handle status messages for --list-keys.
+ ''' Handle status messages for --list-keys, --list-sigs.
Handle pub and uid (relating the latter to the former).
@@ -455,7 +461,6 @@
crt = X.509 certificate
crs = X.509 certificate and private key available
- ssb = secret subkey (secondary key)
uat = user attribute (same as user id except for field 10).
sig = signature
rev = revocation signature
@@ -465,7 +470,7 @@
'''
UID_INDEX = 9
- FIELDS = 'type trust length algo keyid date expires dummy ownertrust uid'.split()
+ FIELDS = 'type trust length algo keyid date expires dummy ownertrust uid sig'.split()
def __init__(self, gpg):
super(ListKeys, self).__init__(gpg)
@@ -485,7 +490,7 @@
def fpr(self, args):
fp = args[9]
- if fp in self.key_map:
+ if fp in self.key_map: # pragma: no cover
raise ValueError('Unexpected fingerprint collision: %s' % fp)
if not self.in_subkey:
self.curkey['fingerprint'] = fp
@@ -500,6 +505,14 @@
self.curkey['subkeys'].append(subkey)
self.in_subkey = True
+ def ssb(self, args):
+ subkey = [args[4], None] # keyid, type
+ self.curkey['subkeys'].append(subkey)
+ self.in_subkey = True
+
+ def sig(self, args):
+ # keyid, uid, sigclass
+ self.curkey['sigs'].append((args[4], args[9], args[10]))
class ScanKeys(ListKeys):
''' Handle status messages for --with-fingerprint.'''
@@ -563,13 +576,13 @@
elif key == "END_ENCRYPTION":
self.status = 'encryption ok'
self.ok = True
- elif key == "INV_RECP":
+ elif key == "INV_RECP": # pragma: no cover
self.status = 'invalid recipient'
- elif key == "KEYEXPIRED":
+ elif key == "KEYEXPIRED": # pragma: no cover
self.status = 'key expired'
- elif key == "SIG_CREATED":
+ elif key == "SIG_CREATED": # pragma: no cover
self.status = 'sig created'
- elif key == "SIGEXPIRED":
+ elif key == "SIGEXPIRED": # pragma: no cover
self.status = 'sig expired'
else:
Verify.handle_status(self, key, value)
@@ -605,7 +618,11 @@
For now, just use an existing class to base it on - if needed, we
can override handle_status for more specific message handling.
"""
- pass
+ def handle_status(self, key, value):
+ if key in ("EXPORTED", "EXPORT_RES"):
+ pass
+ else:
+ super(ExportResult, self).handle_status(key, value)
class DeleteResult(object):
"Handle status messages for --delete-key and --delete-secret-key"
@@ -623,10 +640,10 @@
}
def handle_status(self, key, value):
- if key == "DELETE_PROBLEM":
+ if key == "DELETE_PROBLEM": # pragma: no cover
self.status = self.problem_reason.get(value,
"Unknown error: %r" % value)
- else:
+ else: # pragma: no cover
raise ValueError("Unknown status message: %r" % key)
def __nonzero__(self):
@@ -655,16 +672,16 @@
"SC_OP_FAILURE", "SC_OP_SUCCESS", "PROGRESS",
"PINENTRY_LAUNCHED"):
pass
- elif key in ("KEYEXPIRED", "SIGEXPIRED"):
+ elif key in ("KEYEXPIRED", "SIGEXPIRED"): # pragma: no cover
self.status = 'key expired'
- elif key == "KEYREVOKED":
+ elif key == "KEYREVOKED": # pragma: no cover
self.status = 'key revoked'
elif key == "SIG_CREATED":
(self.type,
algo, self.hash_algo, cls,
self.timestamp, self.fingerprint
) = value.split()
- else:
+ else: # pragma: no cover
raise ValueError("Unknown status message: %r" % key)
VERSION_RE = re.compile(r'gpg \(GnuPG\) (\d+(\.\d+)*)'.encode('ascii'), re.I)
@@ -720,7 +737,7 @@
self.secret_keyring = secret_keyring
self.verbose = verbose
self.use_agent = use_agent
- if isinstance(options, str):
+ if isinstance(options, str): # pragma: no cover
options = [options]
self.options = options
# Changed in 0.3.7 to use Latin-1 encoding rather than
@@ -730,14 +747,19 @@
self.encoding = 'latin-1'
if gnupghome and not os.path.isdir(self.gnupghome):
os.makedirs(self.gnupghome,0x1C0)
- p = self._open_subprocess(["--version"])
+ try:
+ p = self._open_subprocess(["--version"])
+ except OSError:
+ msg = 'Unable to run gpg - it may not be available.'
+ logger.exception(msg)
+ raise OSError(msg)
result = self.result_map['verify'](self) # any result will do for this
self._collect_output(p, result, stdin=p.stdin)
- if p.returncode != 0:
+ if p.returncode != 0: # pragma: no cover
raise ValueError("Error invoking gpg: %s: %s" % (p.returncode,
result.stderr))
m = VERSION_RE.match(result.data)
- if not m:
+ if not m: # pragma: no cover
self.version = None
else:
dot = '.'.encode('ascii')
@@ -761,7 +783,7 @@
cmd.extend(['--secret-keyring', no_quote(fn)])
if passphrase:
cmd.extend(['--batch', '--passphrase-fd', '0'])
- if self.use_agent:
+ if self.use_agent: # pragma: no cover
cmd.append('--use-agent')
if self.options:
cmd.extend(self.options)
@@ -772,13 +794,13 @@
# Internal method: open a pipe to a GPG subprocess and return
# the file objects for communicating with it.
cmd = self.make_args(args, passphrase)
- if self.verbose:
+ if self.verbose: # pragma: no cover
pcmd = ' '.join(cmd)
print(pcmd)
logger.debug("%s", cmd)
if not STARTUPINFO:
si = None
- else:
+ else: # pragma: no cover
si = STARTUPINFO()
si.dwFlags = STARTF_USESHOWWINDOW
si.wShowWindow = SW_HIDE
@@ -798,7 +820,7 @@
break
lines.append(line)
line = line.rstrip()
- if self.verbose:
+ if self.verbose: # pragma: no cover
print(line)
logger.debug("%s", line)
if line[0:9] == '[GNUPG:] ':
@@ -855,7 +877,7 @@
if stdin is not None:
try:
stdin.close()
- except IOError:
+ except IOError: # pragma: no cover
pass
stderr.close()
stdout.close()
@@ -865,7 +887,7 @@
# Handle a basic data call - pass data to GPG, handle the output
# including status information. Garbage In, Garbage Out :)
p = self._open_subprocess(args, passphrase is not None)
- if not binary:
+ if not binary: # pragma: no cover
stdin = codecs.getwriter(self.encoding)(p.stdin)
else:
stdin = p.stdin
@@ -890,13 +912,13 @@
if os.path.exists(output):
# We need to avoid an overwrite confirmation message
args.extend(['--batch', '--yes'])
- args.extend(['--output', output])
+ args.extend(['--output', no_quote(output)])
def sign_file(self, file, keyid=None, passphrase=None, clearsign=True,
detach=False, binary=False, output=None):
"""sign file"""
logger.debug("sign_file: %s", file)
- if binary:
+ if binary: # pragma: no cover
args = ['-s']
else:
args = ['-sa']
@@ -920,7 +942,7 @@
if passphrase:
_write_passphrase(stdin, passphrase, self.encoding)
writer = _threaded_copy_data(file, stdin)
- except IOError:
+ except IOError: # pragma: no cover
logging.exception("error writing message")
writer = None
self._collect_output(p, result, writer, stdin)
@@ -1078,9 +1100,9 @@
def delete_keys(self, fingerprints, secret=False):
which='key'
- if secret:
+ if secret: # pragma: no cover
which='secret-key'
- if _is_sequence(fingerprints):
+ if _is_sequence(fingerprints): # pragma: no cover
fingerprints = [no_quote(s) for s in fingerprints]
else:
fingerprints = [no_quote(fingerprints)]
@@ -1103,7 +1125,7 @@
args = ['--export%s' % which]
if armor:
args.append('--armor')
- if minimal:
+ if minimal: # pragma: no cover
args.extend(['--export-options','export-minimal'])
args.extend(keyids)
p = self._open_subprocess(args)
@@ -1113,7 +1135,11 @@
result = self.result_map['export'](self)
self._collect_output(p, result, stdin=p.stdin)
logger.debug('export_keys result: %r', result.data)
- return result.data.decode(self.encoding, self.decode_errors)
+ # Issue #49: Return bytes if armor not specified, else text
+ result = result.data
+ if armor:
+ result = result.decode(self.encoding, self.decode_errors)
+ return result
def _get_list_output(self, p, kind):
# Get the response information
@@ -1121,22 +1147,22 @@
self._collect_output(p, result, stdin=p.stdin)
lines = result.data.decode(self.encoding,
self.decode_errors).splitlines()
- valid_keywords = 'pub uid sec fpr sub'.split()
+ valid_keywords = 'pub uid sec fpr sub ssb sig'.split()
for line in lines:
- if self.verbose:
+ if self.verbose: # pragma: no cover
print(line)
logger.debug("line: %r", line.rstrip())
- if not line:
+ if not line: # pragma: no cover
break
L = line.strip().split(':')
- if not L:
+ if not L: # pragma: no cover
continue
keyword = L[0]
if keyword in valid_keywords:
getattr(result, keyword)(L)
return result
- def list_keys(self, secret=False, keys=None):
+ def list_keys(self, secret=False, keys=None, sigs=False):
""" list the keys currently in the keyring
>>> import shutil
@@ -1153,7 +1179,10 @@
"""
- which='keys'
+ if sigs:
+ which = 'sigs'
+ else:
+ which='keys'
if secret:
which='secret-keys'
args = ['--list-%s' % which, '--fixed-list-mode',
@@ -1208,13 +1237,13 @@
self.decode_errors).splitlines()
valid_keywords = ['pub', 'uid']
for line in lines:
- if self.verbose:
+ if self.verbose: # pragma: no cover
print(line)
logger.debug('line: %r', line.rstrip())
if not line: # sometimes get blank lines on Windows
continue
L = line.strip().split(':')
- if not L:
+ if not L: # pragma: no cover
continue
keyword = L[0]
if keyword in valid_keywords:
@@ -1312,11 +1341,11 @@
args.append('--armor')
if output: # write the output to a file with the specified name
self.set_output_without_confirmation(args, output)
- if sign is True:
+ if sign is True: # pragma: no cover
args.append('--sign')
- elif sign:
+ elif sign: # pragma: no cover
args.extend(['--sign', '--default-key', no_quote(sign)])
- if always_trust:
+ if always_trust: # pragma: no cover
args.append('--always-trust')
result = self.result_map['crypt'](self)
self._handle_io(args, file, result, passphrase=passphrase, binary=True)
@@ -1380,7 +1409,7 @@
args = ["--decrypt"]
if output: # write the output to a file with the specified name
self.set_output_without_confirmation(args, output)
- if always_trust:
+ if always_trust: # pragma: no cover
args.append("--always-trust")
result = self.result_map['crypt'](self)
self._handle_io(args, file, result, passphrase, binary=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-gnupg-0.3.8/setup.py new/python-gnupg-0.3.9/setup.py
--- old/python-gnupg-0.3.8/setup.py 2015-09-24 19:18:52.000000000 +0200
+++ new/python-gnupg-0.3.9/setup.py 2016-09-09 00:28:05.000000000 +0200
@@ -7,7 +7,7 @@
long_description = "This module allows easy access to GnuPG's key \
management, encryption and signature functionality from Python programs. \
It is intended for use with Python 2.4 or greater.",
- license="""Copyright (C) 2008-2014 by Vinay Sajip. All Rights Reserved. See LICENSE.txt for license.""",
+ license="""Copyright (C) 2008-2016 by Vinay Sajip. All Rights Reserved. See LICENSE.txt for license.""",
version=version,
author="Vinay Sajip",
author_email="vinay_sajip@red-dove.com",
@@ -32,7 +32,6 @@
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules"
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-gnupg-0.3.8/test_gnupg.py new/python-gnupg-0.3.9/test_gnupg.py
--- old/python-gnupg-0.3.8/test_gnupg.py 2015-09-24 19:05:16.000000000 +0200
+++ new/python-gnupg-0.3.9/test_gnupg.py 2016-09-10 09:38:57.000000000 +0200
@@ -2,12 +2,13 @@
"""
A test harness for gnupg.py.
-Copyright (C) 2008-2014 Vinay Sajip. All rights reserved.
+Copyright (C) 2008-2016 Vinay Sajip. All rights reserved.
"""
import doctest
import logging
import os.path
import os
+import re
import shutil
import stat
import sys
@@ -17,7 +18,7 @@
import gnupg
__author__ = "Vinay Sajip"
-__date__ = "$24-Sep-2015 18:05:15$"
+__date__ = "$10-Sep-2016 08:38:57$"
ALL_TESTS = True
@@ -80,16 +81,71 @@
=sqld
-----END PGP PUBLIC KEY BLOCK-----"""
+SIGNED_KEYS="""-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mI0EVcnKUQEEAKWazmfM0kbvDdw7Kos2NARaX67c8iJ3GOBimUvYLj4VR3Mqrm34
+ZdLlS8jCmid+qoisefvGW5uw5Q3gIs0mdEdUpFKlXNiIja/Dg/FHjjJPPCjfzDTh
+Q03EYA7QvOnXZXhYPBqK7NitsNXW4lPnIJdanLx7yMuL+2Xb+tF39mwnABEBAAG0
+LUpvc2h1YSBDYWx2ZXJ0IChBIHRlc3QgdXNlcikgPGpjQGV4YW1wbGUuY29tPoi3
+BBMBCAAhBQJVycpRAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJELxvNQ+z
+0EB2jcED/0lHKaEkyd6cj0Zckf9luIkZ4Hno/vRCquTI7c3aPjS3qmE8mOvKSBCV
++SamPdRM7DdjkdBrrKy2HtiDqbM+1/CdXuQka2SlJWyLCJe48+KWfBpqlY3N4t53
+JjHRitDB+hC8njWTV5prli6EgsBPAF+ZkO0iZhlsMmWdDWgqDpGRiJwEEAEIAAYF
+AlXJym8ACgkQBXzPZYwHT9oiiQQAvPF8ubwRopnXIMDQgSxKyFDM1MI1w/wb4Okd
+/MkMeZSmdcHJ6pEymp5bYciCBuLW+jw0vZWza3YloO/HtuppnF6A9a1UvYcp/diI
+O5qkQqYPlui1PJl7hQ014ioniMfOcC4X/r6PDbC78Pczje0Yh9AOqNGeCyNyNdlc
+pjaHb0m4jQRVycpRAQQAo9JjW75F5wTVVO552cGCZWqZvDyBt9+IkoK9Bc+ggdn5
+6R8QVCihYuaSzcSEN84zHaR3MmGKHraCmCSlfe7w0d41Dlns0P03KMdIZOGrm045
+F8TXdSSPQOv5tA4bz3k2lGD0zB8l4NUWFaZ5fzw2i73FF4O/FwCU8xd/JCKVPkkA
+EQEAAYifBBgBCAAJBQJVycpRAhsMAAoJELxvNQ+z0EB2xLYD/i3tKirQlVB+32WP
+wggstqDp1BlUBmDb+4Gndpg4l7omJTTyOsF26SbYgXZqAdEd5T/UfpEla0DKiBYh
+2/CFYXadkgX/ME+GTetTmD4hHoBNmdXau92buXsIXkwh+JR+RC3cl2U6tWb/MIRd
+zvJiok8W8/FT/QrEjIa2etN2d+KR
+=nNBX
+-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mI0EVcnKNgEEANIVlIUyRXWHP/ljdMEA8B5NxecRCKusUIPxeapk2do5UCZgR1q8
+5wOP4K/+W3Uj85ylOOCNTFYKRozAHsPMAmQ38W93DZYqFbG6d7rwMvz4pVe0wUtj
+SBINoKnoEDZwx3erxFKOkp/5fF3NoYSIx9a0Ds21ESk0TAuH5Tg934YhABEBAAG0
+MVdpbnN0b24gU21pdGggKEEgdGVzdCB1c2VyKSA8d2luc3RvbkBleGFtcGxlLmNv
+bT6ItwQTAQgAIQUCVcnKNgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRAF
+fM9ljAdP2h05A/4vmnxV1MwcOhJTHZys5g2/j5UoZG7V7lPGpJaojSAIVzYXZtwT
+5A7OY8Nl21kIY6gnZlgbTRpHN8Qq2wRKAyW5o6wQvuN16CW4bmGjoHYRGPqkeM0w
+G40W/v88JXrYDNNe/68g4pnPsZ3J0oMLbRvCaDQQHXBuZNJrT1sOxl9Of7iNBFXJ
+yjYBBACmHbs0PdOF8NEGc+fEtmdKOSKOkrcvg1wTu1KFFTBFEbseHOCNpx+R6lfO
+ZiZmHGdKeJhTherfjHaY5jmvyDWq5TLZXK61quNsWxmY2zJ0SRwrIG/CWi4bMi5t
+JNc23vMumkz4X5g7x0Ea7xEWkcYBn0H6sZDAtb8d8mrlWkMekQARAQABiJ8EGAEI
+AAkFAlXJyjYCGwwACgkQBXzPZYwHT9pQIwP8D9/VroykSE2J3gy0S6HC287jXqXF
+0zWejUAQtWUSSRx4esqfLE8lfae6+LDHO8D0Bf6YUJmu7ATOZP2/TIas7JrNvXWc
+NKWl2MHEAGUYq8utCjZ3dKKhaV7UvcY4PyLIpFteNkOz4wFe6C0Mm+1NYwokIFyh
+zPBq9eFk7Xx9Wrc=
+=HT6N
+-----END PGP PUBLIC KEY BLOCK-----
+"""
+
+
def is_list_with_len(o, n):
return isinstance(o, list) and len(o) == n
+BASE64_PATTERN = re.compile(r'^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$', re.I)
+
+def get_key_data(s):
+ lines = s.split('\n')
+ result = ''
+ for line in lines:
+ m = BASE64_PATTERN.match(line)
+ if m:
+ result += line
+ return result
+
def compare_keys(k1, k2):
"Compare ASCII keys"
- k1 = k1.split('\n')
- k2 = k2.split('\n')
- del k1[1] # remove version lines
- del k2[1]
- return k1 != k2
+ # See issue #57: we need to compare only the actual key data,
+ # ignoring things like spurious blank lines
+ return get_key_data(k1) != get_key_data(k2)
class GPGTestCase(unittest.TestCase):
def setUp(self):
@@ -102,12 +158,12 @@
self.gpg = gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY)
v = gpg.version
if v:
- if v >= (2,):
+ if v >= (2,): # pragma: no cover
gpg.options = ['--debug-quick-random']
else:
gpg.options = ['--quick-random']
self.test_fn = test_fn = 'random_binary_data'
- if not os.path.exists(test_fn):
+ if not os.path.exists(test_fn): # pragma: no cover
data_file = open(test_fn, 'wb')
data_file.write(os.urandom(5120 * 1024))
data_file.close()
@@ -237,14 +293,36 @@
for _, _, sfp in key_info['subkeys']:
self.assertTrue(sfp in public_keys.key_map)
self.assertTrue(public_keys.key_map[sfp] is key_info)
+
+ # now test with sigs=True
+ public_keys_sigs = self.gpg.list_keys(sigs=True)
+ self.assertTrue(is_list_with_len(public_keys_sigs, 1),
+ "1-element list expected")
+ key_info = public_keys_sigs[0]
+ fp = key_info['fingerprint']
+ self.assertTrue(fp in public_keys_sigs.key_map)
+ self.assertTrue(public_keys_sigs.key_map[fp] is key_info)
+ self.assertTrue(is_list_with_len(key_info['sigs'], 2))
+ for siginfo in key_info['sigs']:
+ self.assertTrue(len(siginfo), 3)
+ for _, _, sfp in key_info['subkeys']:
+ self.assertTrue(sfp in public_keys_sigs.key_map)
+ self.assertTrue(public_keys_sigs.key_map[sfp] is key_info)
+
private_keys = self.gpg.list_keys(secret=True)
self.assertTrue(is_list_with_len(private_keys, 1),
"1-element list expected")
+ self.assertEqual(len(private_keys.fingerprints), 1)
# Now do the same test, but using keyring and secret_keyring arguments
+ pkn = 'pubring.gpg'
+ skn = 'secring.gpg'
hd = os.path.join(os.getcwd(), 'keys')
+ if os.name == 'posix':
+ pkn = os.path.join(hd, pkn)
+ skn = os.path.join(hd, skn)
gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY,
- keyring=os.path.join(hd, 'pubring.gpg'),
- secret_keyring=os.path.join(hd, 'secring.gpg'))
+ keyring=pkn, secret_keyring=skn)
+ logger.debug('Using keyring and secret_keyring arguments')
public_keys_2 = gpg.list_keys()
self.assertEqual(public_keys_2, public_keys)
private_keys_2 = gpg.list_keys(secret=True)
@@ -283,6 +361,20 @@
'Donna Davis
participants (1)
-
root@hilbert.suse.de