Hello community,

here is the log from the commit of package python-gnupg for openSUSE:Factory 
checked in at 2013-12-16 07:08:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-gnupg (Old)
 and      /work/SRC/openSUSE:Factory/.python-gnupg.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-gnupg"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-gnupg/python-gnupg.changes        
2013-01-24 10:36:41.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python-gnupg.new/python-gnupg.changes   
2013-12-16 07:09:00.000000000 +0100
@@ -1,0 +2,11 @@
+Wed Dec 11 00:49:21 UTC 2013 - [email protected]
+
+- Update to version 0.3.5
+  + Added shell quoting to guard against shell injection.
+  + Fixed issues #76, #77, #78, #79 and #80.
+- Changes from 0.3.4
+  + Addresses #65, #66, #67, #68 and #70.
+- Changes from 0.3.3
+  + Addresses issues #57, #61, #62 and #63.
+
+-------------------------------------------------------------------

Old:
----
  python-gnupg-0.3.2.tar.gz

New:
----
  python-gnupg-0.3.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-gnupg.spec ++++++
--- /var/tmp/diff_new_pack.aW0EOB/_old  2013-12-16 07:09:01.000000000 +0100
+++ /var/tmp/diff_new_pack.aW0EOB/_new  2013-12-16 07:09:01.000000000 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python-gnupg
-Version:        0.3.2
+Version:        0.3.5
 Release:        0
 Url:            http://code.google.com/p/python-gnupg/
 Summary:        A wrapper for the Gnu Privacy Guard (GPG or GnuPG)

++++++ python-gnupg-0.3.2.tar.gz -> python-gnupg-0.3.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.2/LICENSE 
new/python-gnupg-0.3.5/LICENSE
--- old/python-gnupg-0.3.2/LICENSE      2012-02-08 10:57:01.000000000 +0100
+++ new/python-gnupg-0.3.5/LICENSE      2013-02-08 15:09:00.000000000 +0100
@@ -1,4 +1,4 @@
-Copyright (c) 2008-2012 by Vinay Sajip.
+Copyright (c) 2008-2013 by Vinay Sajip.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.2/PKG-INFO 
new/python-gnupg-0.3.5/PKG-INFO
--- old/python-gnupg-0.3.2/PKG-INFO     2013-01-17 13:55:28.000000000 +0100
+++ new/python-gnupg-0.3.5/PKG-INFO     2013-08-30 19:11:27.000000000 +0200
@@ -1,12 +1,12 @@
 Metadata-Version: 1.0
 Name: python-gnupg
-Version: 0.3.2
+Version: 0.3.5
 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: [email protected]
-License: Copyright (C) 2008-2012 by Vinay Sajip. All Rights Reserved. See 
LICENSE for license.
-Download-URL: 
http://python-gnupg.googlecode.com/files/python-gnupg-0.3.2.tar.gz
+License: Copyright (C) 2008-2013 by Vinay Sajip. All Rights Reserved. See 
LICENSE for license.
+Download-URL: 
http://python-gnupg.googlecode.com/files/python-gnupg-0.3.5.tar.gz
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.2/gnupg.py 
new/python-gnupg-0.3.5/gnupg.py
--- old/python-gnupg-0.3.2/gnupg.py     2013-01-16 23:34:46.000000000 +0100
+++ new/python-gnupg-0.3.5/gnupg.py     2013-08-30 19:10:36.000000000 +0200
@@ -33,9 +33,9 @@
 """
 import locale
 
-__version__ = "0.3.2"
+__version__ = "0.3.5"
 __author__ = "Vinay Sajip"
-__date__  = "$16-Jan-2013 15:21:59$"
+__date__  = "$30-Aug-2013 18:10:36$"
 
 try:
     from io import StringIO
@@ -62,13 +62,58 @@
 try:
     unicode
     _py3k = False
+    string_types = basestring
+    text_type = unicode
 except NameError:
     _py3k = True
+    string_types = str
+    text_type = str
 
 logger = logging.getLogger(__name__)
 if not logger.handlers:
     logger.addHandler(NullHandler())
 
+# We use the test below because it works for Jython as well as CPython
+if os.path.__name__ == 'ntpath':
+    # On Windows, we don't need shell quoting, other than worrying about
+    # paths with spaces in them.
+    def shell_quote(s):
+        return '"%s"' % s
+else:
+    # Section copied from sarge
+
+    # This regex determines which shell input needs quoting
+    # because it may be unsafe
+    UNSAFE = re.compile(r'[^\w%+,./:=@-]')
+
+    def shell_quote(s):
+        """
+        Quote text so that it is safe for Posix command shells.
+
+        For example, "*.py" would be converted to "'*.py'". If the text is
+        considered safe it is returned unquoted.
+
+        :param s: The value to quote
+        :type s: str (or unicode on 2.x)
+        :return: A safe version of the input, from the point of view of Posix
+                 command shells
+        :rtype: The passed-in type
+        """
+        if not isinstance(s, string_types):
+            raise TypeError('Expected string type, got %s' % type(s))
+        if not s:
+            result = "''"
+        elif len(s) >= 2 and (s[0], s[-1]) == ("'", "'"):
+            result = '"%s"' % s.replace('"', r'\"')
+        elif not UNSAFE.search(s):
+            result = s
+        else:
+            result = "'%s'" % s.replace("'", "'\"'\"'")
+        return result
+
+    # end of sarge code
+
+
 def _copy_data(instream, outstream):
     # Copy one stream to another
     sent = 0
@@ -78,7 +123,7 @@
         enc = 'ascii'
     while True:
         data = instream.read(1024)
-        if len(data) == 0:
+        if not data:
             break
         sent += len(data)
         logger.debug("sending chunk (%d): %r", sent, data[:256])
@@ -111,16 +156,16 @@
     logger.debug("Wrote passphrase: %r", passphrase)
 
 def _is_sequence(instance):
-    return isinstance(instance,list) or isinstance(instance,tuple)
+    return isinstance(instance, (list, tuple, set, frozenset))
 
 def _make_binary_stream(s, encoding):
+    if _py3k:
+        if isinstance(s, str):
+            s = s.encode(encoding)
+    else:
+        if type(s) is not str:
+            s = s.encode(encoding)
     try:
-        if _py3k:
-            if isinstance(s, str):
-                s = s.encode(encoding)
-        else:
-            if type(s) is not str:
-                s = s.encode(encoding)
         from io import BytesIO
         rv = BytesIO(s)
     except ImportError:
@@ -150,6 +195,7 @@
         self.fingerprint = self.creation_date = self.timestamp = None
         self.signature_id = self.key_id = None
         self.username = None
+        self.key_status = None
         self.status = None
         self.pubkey_fingerprint = None
         self.expire_timestamp = None
@@ -167,13 +213,26 @@
             self.trust_text = key
             self.trust_level = self.TRUST_LEVELS[key]
         elif key in ("RSA_OR_IDEA", "NODATA", "IMPORT_RES", "PLAINTEXT",
-                   "PLAINTEXT_LENGTH", "POLICY_URL", "DECRYPTION_INFO",
-                   "DECRYPTION_OKAY", "INV_SGNR"):
+                     "PLAINTEXT_LENGTH", "POLICY_URL", "DECRYPTION_INFO",
+                     "DECRYPTION_OKAY", "INV_SGNR", "FILE_START", "FILE_ERROR",
+                     "FILE_DONE", "PKA_TRUST_GOOD", "PKA_TRUST_BAD", "BADMDC",
+                     "GOODMDC", "NO_SGNR"):
             pass
         elif key == "BADSIG":
             self.valid = False
             self.status = 'signature bad'
             self.key_id, self.username = value.split(None, 1)
+        elif key == "ERRSIG":
+            self.valid = False
+            (self.key_id,
+             algo, hash_algo,
+             cls,
+             self.timestamp) = value.split()[:5]
+            self.status = 'signature error'
+        elif key == "EXPSIG":
+            self.valid = False
+            self.status = 'signature expired'
+            self.key_id, self.username = value.split(None, 1)
         elif key == "GOODSIG":
             self.valid = True
             self.status = 'signature good'
@@ -189,13 +248,6 @@
         elif key == "SIG_ID":
             (self.signature_id,
              self.creation_date, self.timestamp) = value.split()
-        elif key == "ERRSIG":
-            self.valid = False
-            (self.key_id,
-             algo, hash_algo,
-             cls,
-             self.timestamp) = value.split()[:5]
-            self.status = 'signature error'
         elif key == "DECRYPTION_FAILED":
             self.valid = False
             self.key_id = value
@@ -204,17 +256,21 @@
             self.valid = False
             self.key_id = value
             self.status = 'no public key'
-        elif key in ("KEYEXPIRED", "SIGEXPIRED"):
+        elif key in ("KEYEXPIRED", "SIGEXPIRED", "KEYREVOKED"):
             # 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.
+            # the relevant flag is EXPKEYSIG or REVKEYSIG.
             pass
         elif key in ("EXPKEYSIG", "REVKEYSIG"):
             # signed with expired or revoked key
             self.valid = False
             self.key_id = value.split()[0]
-            self.status = (('%s %s') % (key[:3], key[3:])).lower()
+            if key == "EXPKEYSIG":
+                self.key_status = 'signing key has expired'
+            else:
+                self.key_status = 'signing key was revoked'
+            self.status = self.key_status
         else:
             raise ValueError("Unknown status message: %r" % key)
 
@@ -302,6 +358,21 @@
         return ', '.join(l)
 
 ESCAPE_PATTERN = re.compile(r'\\x([0-9a-f][0-9a-f])', re.I)
+BASIC_ESCAPES = {
+    r'\n': '\n',
+    r'\r': '\r',
+    r'\f': '\f',
+    r'\v': '\v',
+    r'\b': '\b',
+    r'\0': '\0',
+}
+
+class SendResult(object):
+    def __init__(self, gpg):
+        self.gpg = gpg
+
+    def handle_status(self, key, value):
+        logger.debug('SendResult: %s: %s', key, value)
 
 class ListKeys(list):
     ''' Handle status messages for --list-keys.
@@ -349,6 +420,8 @@
     def uid(self, args):
         uid = args[9]
         uid = ESCAPE_PATTERN.sub(lambda m: chr(int(m.group(1), 16)), uid)
+        for k, v in BASIC_ESCAPES.items():
+            uid = uid.replace(k, v)
         self.curkey['uids'].append(uid)
         self.uids.append(uid)
 
@@ -359,6 +432,40 @@
     def handle_status(self, key, value):
         pass
 
+class SearchKeys(list):
+    ''' Handle status messages for --search-keys.
+
+        Handle pub and uid (relating the latter to the former).
+
+        Don't care about the rest
+    '''
+    def __init__(self, gpg):
+        self.gpg = gpg
+        self.curkey = None
+        self.fingerprints = []
+        self.uids = []
+
+    def pub(self, args):
+        vars = ("""
+            type keyid algo length date expires
+        """).split()
+        self.curkey = {}
+        for i in range(len(vars)):
+            self.curkey[vars[i]] = args[i]
+        self.curkey['uids'] = []
+        self.append(self.curkey)
+
+    def uid(self, args):
+        uid = args[1]
+        uid = ESCAPE_PATTERN.sub(lambda m: chr(int(m.group(1), 16)), uid)
+        for k, v in BASIC_ESCAPES.items():
+            uid = uid.replace(k, v)
+        self.curkey['uids'].append(uid)
+        self.uids.append(uid)
+
+    def handle_status(self, key, value):
+        pass
+
 class Crypt(Verify):
     "Handle status messages for --encrypt and --decrypt"
     def __init__(self, gpg):
@@ -379,7 +486,7 @@
     def handle_status(self, key, value):
         if key in ("ENC_TO", "USERID_HINT", "GOODMDC", "END_DECRYPTION",
                    "BEGIN_SIGNING", "NO_SECKEY", "ERROR", "NODATA",
-                   "CARDCTRL"):
+                   "CARDCTRL", "BADMDC", "SC_OP_FAILURE", "SC_OP_SUCCESS"):
             # in the case of ERROR, this is because a more specific error
             # message will have come first
             pass
@@ -446,7 +553,7 @@
     problem_reason = {
         '1': 'No such key',
         '2': 'Must delete secret key first',
-        '3': 'Ambigious specification',
+        '3': 'Ambiguous specification',
     }
 
     def handle_status(self, key, value):
@@ -456,11 +563,18 @@
         else:
             raise ValueError("Unknown status message: %r" % key)
 
+    def __nonzero__(self):
+        return self.status == 'ok'
+
+    __bool__ = __nonzero__
+
+
 class Sign(object):
     "Handle status messages for --sign"
     def __init__(self, gpg):
         self.gpg = gpg
         self.type = None
+        self.hash_algo = None
         self.fingerprint = None
 
     def __nonzero__(self):
@@ -473,16 +587,19 @@
 
     def handle_status(self, key, value):
         if key in ("USERID_HINT", "NEED_PASSPHRASE", "BAD_PASSPHRASE",
-                   "GOOD_PASSPHRASE", "BEGIN_SIGNING", "CARDCTRL", "INV_SGNR"):
+                   "GOOD_PASSPHRASE", "BEGIN_SIGNING", "CARDCTRL", "INV_SGNR",
+                   "KEYEXPIRED", "SIGEXPIRED", "KEYREVOKED", "NO_SGNR",
+                   "MISSING_PASSPHRASE", "SC_OP_FAILURE", "SC_OP_SUCCESS"):
             pass
         elif key == "SIG_CREATED":
             (self.type,
-             algo, hashalgo, cls,
+             algo, self.hash_algo, cls,
              self.timestamp, self.fingerprint
              ) = value.split()
         else:
             raise ValueError("Unknown status message: %r" % key)
 
+VERSION_RE = re.compile(r'gpg \(GnuPG\) (\d+(\.\d+)*)'.encode('utf-8'), re.I)
 
 class GPG(object):
 
@@ -493,27 +610,43 @@
         'delete': DeleteResult,
         'generate': GenKey,
         'import': ImportResult,
+        'send': SendResult,
         'list': ListKeys,
+        'search': SearchKeys,
         'sign': Sign,
         'verify': Verify,
     }
 
     "Encapsulate access to the gpg executable"
     def __init__(self, gpgbinary='gpg', gnupghome=None, verbose=False,
-                 use_agent=False, keyring=None, options=None):
+                 use_agent=False, keyring=None, options=None,
+                 secret_keyring=None):
         """Initialize a GPG process wrapper.  Options are:
 
         gpgbinary -- full pathname for GPG binary.
 
         gnupghome -- full pathname to where we can find the public and
         private keyrings.  Default is whatever gpg defaults to.
-        keyring -- name of alternative keyring file to use. If specified,
-        the default keyring is not used.
+        keyring -- name of alternative keyring file to use, or list of such
+        keyrings. If specified, the default keyring is not used.
         options =-- a list of additional options to pass to the GPG binary.
+        secret_keyring -- name of alternative secret keyring file to use, or
+        list of such keyrings.
         """
         self.gpgbinary = gpgbinary
         self.gnupghome = gnupghome
+        if keyring:
+            # Allow passing a string or another iterable. Make it uniformly
+            # a list of keyring filenames
+            if isinstance(keyring, string_types):
+                keyring = [keyring]
         self.keyring = keyring
+        if secret_keyring:
+            # Allow passing a string or another iterable. Make it uniformly
+            # a list of keyring filenames
+            if isinstance(secret_keyring, string_types):
+                secret_keyring = [secret_keyring]
+        self.secret_keyring = secret_keyring
         self.verbose = verbose
         self.use_agent = use_agent
         if isinstance(options, str):
@@ -522,6 +655,10 @@
         self.encoding = locale.getpreferredencoding()
         if self.encoding is None: # This happens on Jython!
             self.encoding = sys.stdin.encoding
+        if self.encoding is None:
+            logger.warning('No encoding found via locale.getpreferredencoding '
+                           'or sys.stdin.encoding, defaulting to utf-8.')
+            self.encoding = 'utf-8'
         if gnupghome and not os.path.isdir(self.gnupghome):
             os.makedirs(self.gnupghome,0x1C0)
         p = self._open_subprocess(["--version"])
@@ -530,6 +667,12 @@
         if p.returncode != 0:
             raise ValueError("Error invoking gpg: %s: %s" % (p.returncode,
                                                              result.stderr))
+        m = VERSION_RE.match(result.data)
+        if not m:
+            self.version = None
+        else:
+            dot = '.'.encode('utf-8')
+            self.version = tuple([int(s) for s in m.groups()[0].split(dot)])
 
     def make_args(self, args, passphrase):
         """
@@ -539,9 +682,14 @@
         """
         cmd = [self.gpgbinary, '--status-fd 2 --no-tty']
         if self.gnupghome:
-            cmd.append('--homedir "%s" ' % self.gnupghome)
+            cmd.append('--homedir %s' % shell_quote(self.gnupghome))
         if self.keyring:
-            cmd.append('--no-default-keyring --keyring "%s" ' % self.keyring)
+            cmd.append('--no-default-keyring')
+            for fn in self.keyring:
+                cmd.append('--keyring %s' % shell_quote(fn))
+        if self.secret_keyring:
+            for fn in self.secret_keyring:
+                cmd.append('--secret-keyring %s' % shell_quote(fn))
         if passphrase:
             cmd.append('--batch --passphrase-fd 0')
         if self.use_agent:
@@ -635,7 +783,7 @@
         stderr.close()
         stdout.close()
 
-    def _handle_io(self, args, file, result, passphrase=None, binary=False):
+    def _handle_io(self, args, fileobj, result, passphrase=None, binary=False):
         "Handle a call to GPG - pass input data, collect output data"
         # Handle a basic data call - pass data to GPG, handle the output
         # including status information. Garbage In, Garbage Out :)
@@ -646,7 +794,7 @@
             stdin = p.stdin
         if passphrase:
             _write_passphrase(stdin, passphrase, self.encoding)
-        writer = _threaded_copy_data(file, stdin)
+        writer = _threaded_copy_data(fileobj, stdin)
         self._collect_output(p, result, writer, stdin)
         return result
 
@@ -675,7 +823,7 @@
         elif clearsign:
             args.append("--clearsign")
         if keyid:
-            args.append('--default-key "%s"' % keyid)
+            args.append('--default-key %s' % shell_quote(keyid))
         result = self.result_map['sign'](self)
         #We could use _handle_io here except for the fact that if the
         #passphrase is bad, gpg bails and you can't write the message.
@@ -727,8 +875,8 @@
             logger.debug('Wrote to temp file: %r', s)
             os.write(fd, s)
             os.close(fd)
-            args.append(fn)
-            args.append('"%s"' % data_filename)
+            args.append(shell_quote(fn))
+            args.append(shell_quote(data_filename))
             try:
                 p = self._open_subprocess(args)
                 self._collect_output(p, result, stdin=p.stdin)
@@ -799,7 +947,8 @@
         >>> import shutil
         >>> shutil.rmtree("keys")
         >>> gpg = GPG(gnupghome="keys")
-        >>> result = gpg.recv_keys('pgp.mit.edu', '3FF0DB166A7476EA')
+        >>> os.chmod('keys', 0x1C0)
+        >>> result = gpg.recv_keys('keyserver.ubuntu.com', '92905378')
         >>> assert result
 
         """
@@ -807,20 +956,39 @@
         logger.debug('recv_keys: %r', keyids)
         data = _make_binary_stream("", self.encoding)
         #data = ""
-        args = ['--keyserver', keyserver, '--recv-keys']
-        args.extend(keyids)
+        args = ['--keyserver', shell_quote(keyserver), '--recv-keys']
+        args.extend([shell_quote(k) for k in keyids])
         self._handle_io(args, data, result, binary=True)
         logger.debug('recv_keys result: %r', result.__dict__)
         data.close()
         return result
 
+    def send_keys(self, keyserver, *keyids):
+        """Send a key to a keyserver.
+
+        Note: it's not practical to test this function without sending
+        arbitrary data to live keyservers.
+        """
+        result = self.result_map['send'](self)
+        logger.debug('send_keys: %r', keyids)
+        data = _make_binary_stream('', self.encoding)
+        #data = ""
+        args = ['--keyserver', shell_quote(keyserver), '--send-keys']
+        args.extend([shell_quote(k) for k in keyids])
+        self._handle_io(args, data, result, binary=True)
+        logger.debug('send_keys result: %r', result.__dict__)
+        data.close()
+        return result
+
     def delete_keys(self, fingerprints, secret=False):
         which='key'
         if secret:
             which='secret-key'
         if _is_sequence(fingerprints):
-            fingerprints = ' '.join(fingerprints)
-        args = ['--batch --delete-%s "%s"' % (which, fingerprints)]
+            fingerprints = ' '.join([shell_quote(s) for s in fingerprints])
+        else:
+            fingerprints = shell_quote(fingerprints)
+        args = ['--batch --delete-%s %s' % (which, fingerprints)]
         result = self.result_map['delete'](self)
         p = self._open_subprocess(args)
         self._collect_output(p, result, stdin=p.stdin)
@@ -832,8 +1000,10 @@
         if secret:
             which='-secret-key'
         if _is_sequence(keyids):
-            keyids = ' '.join(['"%s"' % k for k in keyids])
-        args = ["--armor --export%s %s" % (which, keyids)]
+            keyids = ' '.join([shell_quote(k) for k in keyids])
+        else:
+            keyids = shell_quote(keyids)
+        args = ['--armor --export%s %s' % (which, keyids)]
         p = self._open_subprocess(args)
         # gpg --export produces no status-fd output; stdout will be
         # empty in case of failure
@@ -890,6 +1060,46 @@
                 getattr(result, keyword)(L)
         return result
 
+    def search_keys(self, query, keyserver='pgp.mit.edu'):
+        """ search keyserver by query (using --search-keys option)
+
+        >>> import shutil
+        >>> shutil.rmtree('keys')
+        >>> gpg = GPG(gnupghome='keys')
+        >>> os.chmod('keys', 0x1C0)
+        >>> result = gpg.search_keys('<[email protected]>')
+        >>> assert result
+        >>> keyserver = 'keyserver.ubuntu.com'
+        >>> result = gpg.search_keys('<[email protected]>', keyserver)
+        >>> assert result
+
+        """
+
+        args = ['--fixed-list-mode', '--fingerprint', '--with-colons',
+                '--keyserver', shell_quote(keyserver), '--search-keys',
+                shell_quote(query)]
+        p = self._open_subprocess(args)
+
+        # Get the response information
+        result = self.result_map['search'](self)
+        self._collect_output(p, result, stdin=p.stdin)
+        lines = result.data.decode(self.encoding,
+                                   self.decode_errors).splitlines()
+        valid_keywords = ['pub', 'uid']
+        for line in lines:
+            if self.verbose:
+                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:
+                continue
+            keyword = L[0]
+            if keyword in valid_keywords:
+                getattr(result, keyword)(L)
+        return result
+
     def gen_key(self, input):
         """Generate a key; you might use gen_key_input() to create the
         control input.
@@ -919,9 +1129,8 @@
             if str(val).strip():    # skip empty strings
                 parms[key] = val
         parms.setdefault('Key-Type','RSA')
-        parms.setdefault('Key-Length',1024)
+        parms.setdefault('Key-Length',2048)
         parms.setdefault('Name-Real', "Autogenerated Key")
-        parms.setdefault('Name-Comment', "Generated by gnupg.py")
         try:
             logname = os.environ['LOGNAME']
         except KeyError:
@@ -966,21 +1175,26 @@
         "Encrypt the message read from the file-like object 'file'"
         args = ['--encrypt']
         if symmetric:
+            # can't be False or None - could be True or a cipher algo value
+            # such as AES256
             args = ['--symmetric']
+            if symmetric is not True:
+                args.extend(['--cipher-algo', shell_quote(symmetric)])
+            # else use the default, currently CAST5
         else:
             args = ['--encrypt']
             if not _is_sequence(recipients):
                 recipients = (recipients,)
             for recipient in recipients:
-                args.append('--recipient "%s"' % recipient)
-        if armor:   # create ascii-armored output - set to False for binary 
output
+                args.append('--recipient %s' % shell_quote(recipient))
+        if armor:   # create ascii-armored output - False for binary output
             args.append('--armor')
         if output:  # write the output to a file with the specified name
             if os.path.exists(output):
                 os.remove(output) # to avoid overwrite confirmation message
-            args.append('--output "%s"' % output)
+            args.append('--output %s' % shell_quote(output))
         if sign:
-            args.append('--sign --default-key "%s"' % sign)
+            args.append('--sign --default-key %s' % shell_quote(sign))
         if always_trust:
             args.append("--always-trust")
         result = self.result_map['crypt'](self)
@@ -1046,7 +1260,7 @@
         if output:  # write the output to a file with the specified name
             if os.path.exists(output):
                 os.remove(output) # to avoid overwrite confirmation message
-            args.append('--output "%s"' % output)
+            args.append('--output %s' % shell_quote(output))
         if always_trust:
             args.append("--always-trust")
         result = self.result_map['crypt'](self)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.2/setup.py 
new/python-gnupg-0.3.5/setup.py
--- old/python-gnupg-0.3.2/setup.py     2012-10-17 09:01:28.000000000 +0200
+++ new/python-gnupg-0.3.5/setup.py     2013-01-23 12:01:38.000000000 +0100
@@ -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-2012 by Vinay Sajip. All Rights Reserved. 
See LICENSE for license.""",
+    license="""Copyright (C) 2008-2013 by Vinay Sajip. All Rights Reserved. 
See LICENSE for license.""",
     version=version,
     author="Vinay Sajip",
     author_email="[email protected]",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-gnupg-0.3.2/test_gnupg.py 
new/python-gnupg-0.3.5/test_gnupg.py
--- old/python-gnupg-0.3.2/test_gnupg.py        2013-01-16 17:07:23.000000000 
+0100
+++ new/python-gnupg-0.3.5/test_gnupg.py        2013-08-30 19:10:57.000000000 
+0200
@@ -16,12 +16,14 @@
 import gnupg
 
 __author__ = "Vinay Sajip"
-__date__  = "$16-Jan-2013 15:23:54$"
+__date__  = "$30-Aug-2013 18:10:57$"
 
 ALL_TESTS = True
 
 logger = logging.getLogger(__name__)
 
+GPGBINARY = os.environ.get('GPGBINARY', 'gpg')
+
 KEYS_TO_IMPORT = """-----BEGIN PGP PUBLIC KEY BLOCK-----
 Version: GnuPG v1.4.9 (MingW32)
 
@@ -96,7 +98,9 @@
                             "Not a directory: %s" % hd)
             shutil.rmtree(hd)
         self.homedir = hd
-        self.gpg = gnupg.GPG(gnupghome=hd, gpgbinary='gpg')
+        self.gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY)
+        if self.gpg.version and self.gpg.version >= (2,):
+            self.gpg.options = ['--debug-quick-random']
 
     def test_environment(self):
         "Test the environment by ensuring that setup worked"
@@ -125,6 +129,10 @@
             'Name-Comment': 'A test user',
             'Expire-Date': 0,
         }
+        if '--debug-quick-random' in (self.gpg.options or []):
+            # If using the fake RNG, a key isn't regarded as valid
+            # unless its comment has the text (insecure!) in it.
+            params['Name-Comment'] = 'A test user (insecure!)'
         params['Name-Real'] = '%s %s' % (first_name, last_name)
         params['Name-Email'] = ("%s.%s@%s" % (first_name, last_name, 
domain)).lower()
         if passphrase is None:
@@ -175,18 +183,33 @@
         self.assertEqual(uid, 'urn:uuid:731c22c4-830f-422f-80dc-14a9fdae8c19 '
                               '(dummy comment) <[email protected]>')
 
+    def test_key_generation_with_escapes(self):
+        "Test that key generation handles escape characters"
+        cmd = self.gpg.gen_key_input(name_comment='Funny chars: '
+                                                  '\\r\\n\\f\\v\\0\\b',
+                                     name_real='Test Name',
+                                     name_email='[email protected]')
+        result = self.gpg.gen_key(cmd)
+        keys = self.gpg.list_keys()
+        self.assertEqual(len(keys), 1)
+        key = keys[0]
+        uids = key['uids']
+        self.assertEqual(len(uids), 1)
+        uid = uids[0]
+        self.assertEqual(uid, 'Test Name (Funny chars: '
+                              '\r\n\x0c\x0b\x00\x08) <[email protected]>')
+
     def test_key_generation_with_empty_value(self):
         "Test that key generation handles empty values"
         params = {
-            'key_type': 'RSA',
-            'key_length': 1024,
-            'name_comment': ' ', # Not added, so default will appear
+            'key_type': ' ',
+            'key_length': 2048,
         }
         cmd = self.gpg.gen_key_input(**params)
-        self.assertTrue('\nName-Comment: Generated by gnupg.py\n' in cmd)
-        params['name_comment'] = 'A'
+        self.assertTrue('Key-Type: RSA\n' in cmd)
+        params['key_type'] = 'DSA'
         cmd = self.gpg.gen_key_input(**params)
-        self.assertTrue('\nName-Comment: A\n' in cmd)
+        self.assertTrue('Key-Type: DSA\n' in cmd)
         
     def test_list_keys_after_generation(self):
         "Test that after key generation, the generated key is available"
@@ -198,6 +221,15 @@
         private_keys = self.gpg.list_keys(secret=True)
         self.assertTrue(is_list_with_len(private_keys, 1),
                         "1-element list expected")
+        # Now do the same test, but using keyring and secret_keyring arguments
+        hd = os.path.join(os.getcwd(), 'keys')
+        gpg = gnupg.GPG(gnupghome=hd, gpgbinary=GPGBINARY,
+                        keyring=os.path.join(hd, 'pubring.gpg'),
+                        secret_keyring=os.path.join(hd, 'secring.gpg'))
+        public_keys_2 = gpg.list_keys()
+        self.assertEqual(public_keys_2, public_keys)
+        private_keys_2 = gpg.list_keys(secret=True)
+        self.assertEqual(private_keys_2, private_keys)
 
     def test_encryption_and_decryption(self):
         "Test that encryption and decryption works"
@@ -233,6 +265,12 @@
         edata = str(gpg.encrypt(data, None, passphrase='bbrown', 
symmetric=True))
         ddata = gpg.decrypt(edata, passphrase='bbrown')
         self.assertEqual(data, str(ddata))
+        # Test symmetric encryption with non-default cipher
+        data = "chippy was here"
+        edata = str(gpg.encrypt(data, None, passphrase='bbrown',
+                    symmetric='AES256'))
+        ddata = gpg.decrypt(edata, passphrase='bbrown')
+        self.assertEqual(data, str(ddata))
 
     def test_import_and_export(self):
         "Test that key import and export works"
@@ -299,6 +337,7 @@
         self.assertFalse(sig, "Bad passphrase should fail")
         sig = self.gpg.sign(data, keyid=key.fingerprint, passphrase='aable')
         self.assertTrue(sig, "Good passphrase should succeed")
+        self.assertTrue(sig.hash_algo)
         verified = self.gpg.verify(sig.data)
         if key.fingerprint != verified.fingerprint:
             logger.debug("key: %r", key.fingerprint)
@@ -316,6 +355,7 @@
                                  passphrase='aable')
         data_file.close()
         self.assertTrue(sig, "File signing should succeed")
+        self.assertTrue(sig.hash_algo)
         try:
             file = gnupg._make_binary_stream(sig.data, self.gpg.encoding)
             verified = self.gpg.verify_file(file)
@@ -332,6 +372,7 @@
                                  passphrase='aable', detach=True)
         data_file.close()
         self.assertTrue(sig, "File signing should succeed")
+        self.assertTrue(sig.hash_algo)
         try:
             file = gnupg._make_binary_stream(sig.data, self.gpg.encoding)
             verified = self.gpg.verify_file(file, 'random_binary_data')
@@ -411,6 +452,15 @@
                     os.remove(fn)
         logger.debug("test_file_encryption_and_decryption ends")
 
+    def test_search_keys(self):
+        "Test that searching for keys works"
+        r = self.gpg.search_keys('<[email protected]>')
+        self.assertTrue(r)
+        self.assertTrue('Vinay Sajip <[email protected]>' in 
r[0]['uids'])
+        r = self.gpg.search_keys('92905378')
+        self.assertTrue(r)
+        self.assertTrue('Vinay Sajip <[email protected]>' in 
r[0]['uids'])
+
 
 TEST_GROUPS = {
     'sign' : set(['test_signature_verification']),
@@ -419,8 +469,10 @@
     'key' : set(['test_deletion', 'test_import_and_export',
                  'test_list_keys_after_generation',
                  'test_key_generation_with_invalid_key_type',
+                 'test_key_generation_with_escapes',
                  'test_key_generation_with_empty_value',
-                 'test_key_generation_with_colons']),
+                 'test_key_generation_with_colons',
+                 'test_search_keys']),
     'import' : set(['test_import_only']),
     'basic' : set(['test_environment', 'test_list_keys_initial',
                    'test_nogpg', 'test_make_args']),

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to