update gnupg to 0.3.4
This commit is contained in:
parent
44f9c18b95
commit
9e7ea9b328
|
@ -27,15 +27,15 @@ Vinay Sajip to make use of the subprocess module (Steve's version uses os.fork()
|
||||||
and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
|
and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
|
||||||
the previous versions.
|
the previous versions.
|
||||||
|
|
||||||
Modifications Copyright (C) 2008-2012 Vinay Sajip. All rights reserved.
|
Modifications Copyright (C) 2008-2013 Vinay Sajip. All rights reserved.
|
||||||
|
|
||||||
A unittest harness (test_gnupg.py) has also been added.
|
A unittest harness (test_gnupg.py) has also been added.
|
||||||
"""
|
"""
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
__version__ = "0.3.0"
|
__version__ = "0.3.4"
|
||||||
__author__ = "Vinay Sajip"
|
__author__ = "Vinay Sajip"
|
||||||
__date__ = "$12-May-2012 10:49:10$"
|
__date__ = "$05-Jun-2013 09:48:54$"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
@ -46,6 +46,7 @@ import codecs
|
||||||
import locale
|
import locale
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import socket
|
import socket
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from subprocess import PIPE
|
from subprocess import PIPE
|
||||||
|
@ -61,8 +62,12 @@ except ImportError:
|
||||||
try:
|
try:
|
||||||
unicode
|
unicode
|
||||||
_py3k = False
|
_py3k = False
|
||||||
|
string_types = basestring
|
||||||
|
text_type = unicode
|
||||||
except NameError:
|
except NameError:
|
||||||
_py3k = True
|
_py3k = True
|
||||||
|
string_types = str
|
||||||
|
text_type = str
|
||||||
|
|
||||||
logger = logging.getLogger('gajim.c.gnupg')
|
logger = logging.getLogger('gajim.c.gnupg')
|
||||||
if not logger.handlers:
|
if not logger.handlers:
|
||||||
|
@ -77,7 +82,7 @@ def _copy_data(instream, outstream):
|
||||||
enc = 'ascii'
|
enc = 'ascii'
|
||||||
while True:
|
while True:
|
||||||
data = instream.read(1024)
|
data = instream.read(1024)
|
||||||
if len(data) == 0:
|
if not data:
|
||||||
break
|
break
|
||||||
sent += len(data)
|
sent += len(data)
|
||||||
logger.debug("sending chunk (%d): %r", sent, data[:256])
|
logger.debug("sending chunk (%d): %r", sent, data[:256])
|
||||||
|
@ -110,16 +115,16 @@ def _write_passphrase(stream, passphrase, encoding):
|
||||||
logger.debug("Wrote passphrase: %r", passphrase)
|
logger.debug("Wrote passphrase: %r", passphrase)
|
||||||
|
|
||||||
def _is_sequence(instance):
|
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):
|
def _make_binary_stream(s, encoding):
|
||||||
try:
|
|
||||||
if _py3k:
|
if _py3k:
|
||||||
if isinstance(s, str):
|
if isinstance(s, str):
|
||||||
s = s.encode(encoding)
|
s = s.encode(encoding)
|
||||||
else:
|
else:
|
||||||
if type(s) is not str:
|
if type(s) is not str:
|
||||||
s = s.encode(encoding)
|
s = s.encode(encoding)
|
||||||
|
try:
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
rv = BytesIO(s)
|
rv = BytesIO(s)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -129,12 +134,33 @@ def _make_binary_stream(s, encoding):
|
||||||
class Verify(object):
|
class Verify(object):
|
||||||
"Handle status messages for --verify"
|
"Handle status messages for --verify"
|
||||||
|
|
||||||
|
TRUST_UNDEFINED = 0
|
||||||
|
TRUST_NEVER = 1
|
||||||
|
TRUST_MARGINAL = 2
|
||||||
|
TRUST_FULLY = 3
|
||||||
|
TRUST_ULTIMATE = 4
|
||||||
|
|
||||||
|
TRUST_LEVELS = {
|
||||||
|
"TRUST_UNDEFINED" : TRUST_UNDEFINED,
|
||||||
|
"TRUST_NEVER" : TRUST_NEVER,
|
||||||
|
"TRUST_MARGINAL" : TRUST_MARGINAL,
|
||||||
|
"TRUST_FULLY" : TRUST_FULLY,
|
||||||
|
"TRUST_ULTIMATE" : TRUST_ULTIMATE,
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, gpg):
|
def __init__(self, gpg):
|
||||||
self.gpg = gpg
|
self.gpg = gpg
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.fingerprint = self.creation_date = self.timestamp = None
|
self.fingerprint = self.creation_date = self.timestamp = None
|
||||||
self.signature_id = self.key_id = None
|
self.signature_id = self.key_id = None
|
||||||
self.username = None
|
self.username = None
|
||||||
|
self.key_status = None
|
||||||
|
self.status = None
|
||||||
|
self.pubkey_fingerprint = None
|
||||||
|
self.expire_timestamp = None
|
||||||
|
self.sig_timestamp = None
|
||||||
|
self.trust_text = None
|
||||||
|
self.trust_level = None
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
return self.valid
|
return self.valid
|
||||||
|
@ -142,15 +168,30 @@ class Verify(object):
|
||||||
__bool__ = __nonzero__
|
__bool__ = __nonzero__
|
||||||
|
|
||||||
def handle_status(self, key, value):
|
def handle_status(self, key, value):
|
||||||
if key in ("TRUST_UNDEFINED", "TRUST_NEVER", "TRUST_MARGINAL",
|
if key in self.TRUST_LEVELS:
|
||||||
"TRUST_FULLY", "TRUST_ULTIMATE", "RSA_OR_IDEA", "NODATA",
|
self.trust_text = key
|
||||||
"IMPORT_RES", "PLAINTEXT", "PLAINTEXT_LENGTH",
|
self.trust_level = self.TRUST_LEVELS[key]
|
||||||
"POLICY_URL", "DECRYPTION_INFO", "DECRYPTION_OKAY"):
|
elif key in ("RSA_OR_IDEA", "NODATA", "IMPORT_RES", "PLAINTEXT",
|
||||||
|
"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
|
pass
|
||||||
elif key == "BADSIG":
|
elif key == "BADSIG":
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.status = 'signature bad'
|
self.status = 'signature bad'
|
||||||
self.key_id, self.username = value.split(None, 1)
|
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":
|
elif key == "GOODSIG":
|
||||||
self.valid = True
|
self.valid = True
|
||||||
self.status = 'signature good'
|
self.status = 'signature good'
|
||||||
|
@ -166,13 +207,6 @@ class Verify(object):
|
||||||
elif key == "SIG_ID":
|
elif key == "SIG_ID":
|
||||||
(self.signature_id,
|
(self.signature_id,
|
||||||
self.creation_date, self.timestamp) = value.split()
|
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":
|
elif key == "DECRYPTION_FAILED":
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.key_id = value
|
self.key_id = value
|
||||||
|
@ -181,17 +215,21 @@ class Verify(object):
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.key_id = value
|
self.key_id = value
|
||||||
self.status = 'no public key'
|
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
|
# these are useless in verify, since they are spit out for any
|
||||||
# pub/subkeys on the key, not just the one doing the signing.
|
# pub/subkeys on the key, not just the one doing the signing.
|
||||||
# if we want to check for signatures with expired key,
|
# if we want to check for signatures with expired key,
|
||||||
# the relevant flag is EXPKEYSIG.
|
# the relevant flag is EXPKEYSIG or REVKEYSIG.
|
||||||
pass
|
pass
|
||||||
elif key in ("EXPKEYSIG", "REVKEYSIG"):
|
elif key in ("EXPKEYSIG", "REVKEYSIG"):
|
||||||
# signed with expired or revoked key
|
# signed with expired or revoked key
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.key_id = value.split()[0]
|
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:
|
else:
|
||||||
raise ValueError("Unknown status message: %r" % key)
|
raise ValueError("Unknown status message: %r" % key)
|
||||||
|
|
||||||
|
@ -273,11 +311,21 @@ class ImportResult(object):
|
||||||
|
|
||||||
def summary(self):
|
def summary(self):
|
||||||
l = []
|
l = []
|
||||||
l.append('%d imported'%self.imported)
|
l.append('%d imported' % self.imported)
|
||||||
if self.not_imported:
|
if self.not_imported:
|
||||||
l.append('%d not imported'%self.not_imported)
|
l.append('%d not imported' % self.not_imported)
|
||||||
return ', '.join(l)
|
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 ListKeys(list):
|
class ListKeys(list):
|
||||||
''' Handle status messages for --list-keys.
|
''' Handle status messages for --list-keys.
|
||||||
|
|
||||||
|
@ -322,8 +370,12 @@ class ListKeys(list):
|
||||||
self.fingerprints.append(args[9])
|
self.fingerprints.append(args[9])
|
||||||
|
|
||||||
def uid(self, args):
|
def uid(self, args):
|
||||||
self.curkey['uids'].append(args[9])
|
uid = args[9]
|
||||||
self.uids.append(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)
|
||||||
|
|
||||||
def sub(self, args):
|
def sub(self, args):
|
||||||
subkey = [args[4], args[11]]
|
subkey = [args[4], args[11]]
|
||||||
|
@ -352,7 +404,7 @@ class Crypt(Verify):
|
||||||
def handle_status(self, key, value):
|
def handle_status(self, key, value):
|
||||||
if key in ("ENC_TO", "USERID_HINT", "GOODMDC", "END_DECRYPTION",
|
if key in ("ENC_TO", "USERID_HINT", "GOODMDC", "END_DECRYPTION",
|
||||||
"BEGIN_SIGNING", "NO_SECKEY", "ERROR", "NODATA",
|
"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
|
# in the case of ERROR, this is because a more specific error
|
||||||
# message will have come first
|
# message will have come first
|
||||||
pass
|
pass
|
||||||
|
@ -400,7 +452,7 @@ class GenKey(object):
|
||||||
return self.fingerprint or ''
|
return self.fingerprint or ''
|
||||||
|
|
||||||
def handle_status(self, key, value):
|
def handle_status(self, key, value):
|
||||||
if key in ("PROGRESS", "GOOD_PASSPHRASE", "NODATA"):
|
if key in ("PROGRESS", "GOOD_PASSPHRASE", "NODATA", "KEY_NOT_CREATED"):
|
||||||
pass
|
pass
|
||||||
elif key == "KEY_CREATED":
|
elif key == "KEY_CREATED":
|
||||||
(self.type,self.fingerprint) = value.split()
|
(self.type,self.fingerprint) = value.split()
|
||||||
|
@ -419,7 +471,7 @@ class DeleteResult(object):
|
||||||
problem_reason = {
|
problem_reason = {
|
||||||
'1': 'No such key',
|
'1': 'No such key',
|
||||||
'2': 'Must delete secret key first',
|
'2': 'Must delete secret key first',
|
||||||
'3': 'Ambigious specification',
|
'3': 'Ambiguous specification',
|
||||||
}
|
}
|
||||||
|
|
||||||
def handle_status(self, key, value):
|
def handle_status(self, key, value):
|
||||||
|
@ -429,13 +481,19 @@ class DeleteResult(object):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown status message: %r" % key)
|
raise ValueError("Unknown status message: %r" % key)
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
return self.status == 'ok'
|
||||||
|
|
||||||
|
__bool__ = __nonzero__
|
||||||
|
|
||||||
|
|
||||||
class Sign(object):
|
class Sign(object):
|
||||||
"Handle status messages for --sign"
|
"Handle status messages for --sign"
|
||||||
def __init__(self, gpg):
|
def __init__(self, gpg):
|
||||||
self.gpg = gpg
|
self.gpg = gpg
|
||||||
self.type = None
|
self.type = None
|
||||||
|
self.hash_algo = None
|
||||||
self.fingerprint = None
|
self.fingerprint = None
|
||||||
self.status = ''
|
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
return self.fingerprint is not None
|
return self.fingerprint is not None
|
||||||
|
@ -447,18 +505,19 @@ class Sign(object):
|
||||||
|
|
||||||
def handle_status(self, key, value):
|
def handle_status(self, key, value):
|
||||||
if key in ("USERID_HINT", "NEED_PASSPHRASE", "BAD_PASSPHRASE",
|
if key in ("USERID_HINT", "NEED_PASSPHRASE", "BAD_PASSPHRASE",
|
||||||
"GOOD_PASSPHRASE", "BEGIN_SIGNING", "CARDCTRL", "MISSING_PASSPHRASE"):
|
"GOOD_PASSPHRASE", "BEGIN_SIGNING", "CARDCTRL", "INV_SGNR",
|
||||||
|
"KEYEXPIRED", "SIGEXPIRED", "KEYREVOKED", "NO_SGNR",
|
||||||
|
"MISSING_PASSPHRASE", "SC_OP_FAILURE", "SC_OP_SUCCESS"):
|
||||||
pass
|
pass
|
||||||
elif key in ("KEYEXPIRED", "SIGEXPIRED"):
|
|
||||||
self.status = 'key expired'
|
|
||||||
elif key == "SIG_CREATED":
|
elif key == "SIG_CREATED":
|
||||||
(self.type,
|
(self.type,
|
||||||
algo, hashalgo, cls,
|
algo, self.hash_algo, cls,
|
||||||
self.timestamp, self.fingerprint
|
self.timestamp, self.fingerprint
|
||||||
) = value.split()
|
) = value.split()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown status message: %r" % key)
|
raise ValueError("Unknown status message: %r" % key)
|
||||||
|
|
||||||
|
VERSION_RE = re.compile(r'gpg \(GnuPG\) (\d+(\.\d+)*)'.encode('utf-8'), re.I)
|
||||||
|
|
||||||
class GPG(object):
|
class GPG(object):
|
||||||
|
|
||||||
|
@ -476,21 +535,39 @@ class GPG(object):
|
||||||
|
|
||||||
"Encapsulate access to the gpg executable"
|
"Encapsulate access to the gpg executable"
|
||||||
def __init__(self, gpgbinary='gpg', gnupghome=None, verbose=False,
|
def __init__(self, gpgbinary='gpg', gnupghome=None, verbose=False,
|
||||||
use_agent=False, keyring=None):
|
use_agent=False, keyring=None, options=None,
|
||||||
|
secret_keyring=None):
|
||||||
"""Initialize a GPG process wrapper. Options are:
|
"""Initialize a GPG process wrapper. Options are:
|
||||||
|
|
||||||
gpgbinary -- full pathname for GPG binary.
|
gpgbinary -- full pathname for GPG binary.
|
||||||
|
|
||||||
gnupghome -- full pathname to where we can find the public and
|
gnupghome -- full pathname to where we can find the public and
|
||||||
private keyrings. Default is whatever gpg defaults to.
|
private keyrings. Default is whatever gpg defaults to.
|
||||||
keyring -- name of alternative keyring file to use. If specified,
|
keyring -- name of alternative keyring file to use, or list of such
|
||||||
the default keyring is not used.
|
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.gpgbinary = gpgbinary
|
||||||
self.gnupghome = gnupghome
|
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
|
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.verbose = verbose
|
||||||
self.use_agent = use_agent
|
self.use_agent = use_agent
|
||||||
|
if isinstance(options, str):
|
||||||
|
options = [options]
|
||||||
|
self.options = options
|
||||||
self.encoding = locale.getpreferredencoding()
|
self.encoding = locale.getpreferredencoding()
|
||||||
if self.encoding is None: # This happens on Jython!
|
if self.encoding is None: # This happens on Jython!
|
||||||
self.encoding = sys.stdin.encoding
|
self.encoding = sys.stdin.encoding
|
||||||
|
@ -502,21 +579,42 @@ class GPG(object):
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise ValueError("Error invoking gpg: %s: %s" % (p.returncode,
|
raise ValueError("Error invoking gpg: %s: %s" % (p.returncode,
|
||||||
result.stderr))
|
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 _open_subprocess(self, args, passphrase=False):
|
def make_args(self, args, passphrase):
|
||||||
# Internal method: open a pipe to a GPG subprocess and return
|
"""
|
||||||
# the file objects for communicating with it.
|
Make a list of command line elements for GPG. The value of ``args``
|
||||||
|
will be appended. The ``passphrase`` argument needs to be True if
|
||||||
|
a passphrase will be sent to GPG, else False.
|
||||||
|
"""
|
||||||
cmd = [self.gpgbinary, '--status-fd 2 --no-tty']
|
cmd = [self.gpgbinary, '--status-fd 2 --no-tty']
|
||||||
if self.gnupghome:
|
if self.gnupghome:
|
||||||
cmd.append('--homedir "%s" ' % self.gnupghome)
|
cmd.append('--homedir "%s"' % self.gnupghome)
|
||||||
if self.keyring:
|
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"' % fn)
|
||||||
|
if self.secret_keyring:
|
||||||
|
for fn in self.secret_keyring:
|
||||||
|
cmd.append('--secret-keyring "%s"' % fn)
|
||||||
if passphrase:
|
if passphrase:
|
||||||
cmd.append('--batch --passphrase-fd 0')
|
cmd.append('--batch --passphrase-fd 0')
|
||||||
if self.use_agent:
|
if self.use_agent:
|
||||||
cmd.append('--use-agent')
|
cmd.append('--use-agent')
|
||||||
|
if self.options:
|
||||||
|
cmd.extend(self.options)
|
||||||
cmd.extend(args)
|
cmd.extend(args)
|
||||||
cmd = ' '.join(cmd)
|
return cmd
|
||||||
|
|
||||||
|
def _open_subprocess(self, args, passphrase=False):
|
||||||
|
# Internal method: open a pipe to a GPG subprocess and return
|
||||||
|
# the file objects for communicating with it.
|
||||||
|
cmd = ' '.join(self.make_args(args, passphrase))
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
logger.debug("%s", cmd)
|
logger.debug("%s", cmd)
|
||||||
|
@ -597,7 +695,7 @@ class GPG(object):
|
||||||
stderr.close()
|
stderr.close()
|
||||||
stdout.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 call to GPG - pass input data, collect output data"
|
||||||
# Handle a basic data call - pass data to GPG, handle the output
|
# Handle a basic data call - pass data to GPG, handle the output
|
||||||
# including status information. Garbage In, Garbage Out :)
|
# including status information. Garbage In, Garbage Out :)
|
||||||
|
@ -608,7 +706,7 @@ class GPG(object):
|
||||||
stdin = p.stdin
|
stdin = p.stdin
|
||||||
if passphrase:
|
if passphrase:
|
||||||
_write_passphrase(stdin, passphrase, self.encoding)
|
_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)
|
self._collect_output(p, result, writer, stdin)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -758,10 +856,14 @@ class GPG(object):
|
||||||
def recv_keys(self, keyserver, *keyids):
|
def recv_keys(self, keyserver, *keyids):
|
||||||
"""Import a key from a keyserver
|
"""Import a key from a keyserver
|
||||||
|
|
||||||
|
The doctest assertion is skipped in Jython because security permissions
|
||||||
|
may prevent the recv_keys from succeeding.
|
||||||
|
|
||||||
>>> import shutil
|
>>> import shutil
|
||||||
>>> shutil.rmtree("keys")
|
>>> shutil.rmtree("keys")
|
||||||
>>> gpg = GPG(gnupghome="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
|
>>> assert result
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -878,6 +980,7 @@ class GPG(object):
|
||||||
parms = {}
|
parms = {}
|
||||||
for key, val in list(kwargs.items()):
|
for key, val in list(kwargs.items()):
|
||||||
key = key.replace('_','-').title()
|
key = key.replace('_','-').title()
|
||||||
|
if str(val).strip(): # skip empty strings
|
||||||
parms[key] = val
|
parms[key] = val
|
||||||
parms.setdefault('Key-Type','RSA')
|
parms.setdefault('Key-Type','RSA')
|
||||||
parms.setdefault('Key-Length',1024)
|
parms.setdefault('Key-Length',1024)
|
||||||
|
@ -971,9 +1074,6 @@ class GPG(object):
|
||||||
'hello'
|
'hello'
|
||||||
>>> result = gpg.encrypt("hello again",print1)
|
>>> result = gpg.encrypt("hello again",print1)
|
||||||
>>> message = str(result)
|
>>> message = str(result)
|
||||||
>>> result = gpg.decrypt(message)
|
|
||||||
>>> result.status == 'need passphrase'
|
|
||||||
True
|
|
||||||
>>> result = gpg.decrypt(message,passphrase='bar')
|
>>> result = gpg.decrypt(message,passphrase='bar')
|
||||||
>>> result.status in ('decryption failed', 'bad passphrase')
|
>>> result.status in ('decryption failed', 'bad passphrase')
|
||||||
True
|
True
|
||||||
|
@ -983,9 +1083,6 @@ class GPG(object):
|
||||||
True
|
True
|
||||||
>>> str(result)
|
>>> str(result)
|
||||||
'hello again'
|
'hello again'
|
||||||
>>> result = gpg.encrypt("signed hello",print2,sign=print1)
|
|
||||||
>>> result.status == 'need passphrase'
|
|
||||||
True
|
|
||||||
>>> result = gpg.encrypt("signed hello",print2,sign=print1,passphrase='foo')
|
>>> result = gpg.encrypt("signed hello",print2,sign=print1,passphrase='foo')
|
||||||
>>> result.status == 'encryption ok'
|
>>> result.status == 'encryption ok'
|
||||||
True
|
True
|
||||||
|
|
Loading…
Reference in New Issue