diff --git a/lang/python/tests/final.py b/lang/python/tests/final.py index 65375cb8..d0d52dc4 100755 --- a/lang/python/tests/final.py +++ b/lang/python/tests/final.py @@ -1,29 +1,32 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import subprocess import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals -subprocess.check_call([os.path.join(os.getenv('top_srcdir'), - "tests", "start-stop-agent"), "--stop"]) +subprocess.check_call([ + os.path.join(os.getenv('top_srcdir'), "tests", "start-stop-agent"), + "--stop" +]) diff --git a/lang/python/tests/initial.py b/lang/python/tests/initial.py index 49e4f82e..30a8de7a 100755 --- a/lang/python/tests/initial.py +++ b/lang/python/tests/initial.py @@ -1,42 +1,45 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import subprocess import gpg import support +del absolute_import, print_function, unicode_literals + print("Using gpg module from {0!r}.".format(os.path.dirname(gpg.__file__))) -subprocess.check_call([os.path.join(os.getenv('top_srcdir'), - "tests", "start-stop-agent"), "--start"]) +subprocess.check_call([ + os.path.join(os.getenv('top_srcdir'), "tests", "start-stop-agent"), + "--start" +]) with gpg.Context() as c: alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) # Mark alpha as trusted. The signature verification tests expect # this. support.mark_key_trusted(c, alpha) c.op_import(open(support.in_srcdir("encrypt-only.asc"))) c.op_import(open(support.in_srcdir("sign-only.asc"))) diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py index 95df1978..cec13b5e 100644 --- a/lang/python/tests/run-tests.py +++ b/lang/python/tests/run-tests.py @@ -1,112 +1,137 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from __future__ import absolute_import, division +from __future__ import print_function, unicode_literals import argparse import glob import os import subprocess import sys +del absolute_import, division, print_function, unicode_literals + + class SplitAndAccumulate(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): current = getattr(namespace, self.dest, list()) current.extend(values.split()) setattr(namespace, self.dest, current) + parser = argparse.ArgumentParser(description='Run tests.') -parser.add_argument('tests', metavar='TEST', type=str, nargs='+', - help='A test to run') -parser.add_argument('-v', '--verbose', action="store_true", default=False, - help='Be verbose.') -parser.add_argument('-q', '--quiet', action="store_true", default=False, - help='Be quiet.') -parser.add_argument('--interpreters', metavar='PYTHON', type=str, - default=[], action=SplitAndAccumulate, - help='Use these interpreters to run the tests, ' + - 'separated by spaces.') -parser.add_argument('--srcdir', type=str, - default=os.environ.get("srcdir", ""), - help='Location of the tests.') -parser.add_argument('--builddir', type=str, - default=os.environ.get("abs_builddir", ""), - help='Location of the tests.') -parser.add_argument('--python-libdir', type=str, - default=None, - help='Optional location of the in-tree module lib directory.') -parser.add_argument('--parallel', action="store_true", default=False, - help='Ignored. For compatibility with run-tests.scm.') +parser.add_argument( + 'tests', metavar='TEST', type=str, nargs='+', help='A test to run') +parser.add_argument( + '-v', '--verbose', action="store_true", default=False, help='Be verbose.') +parser.add_argument( + '-q', '--quiet', action="store_true", default=False, help='Be quiet.') +parser.add_argument( + '--interpreters', + metavar='PYTHON', + type=str, + default=[], + action=SplitAndAccumulate, + help='Use these interpreters to run the tests, ' + 'separated by spaces.') +parser.add_argument( + '--srcdir', + type=str, + default=os.environ.get("srcdir", ""), + help='Location of the tests.') +parser.add_argument( + '--builddir', + type=str, + default=os.environ.get("abs_builddir", ""), + help='Location of the tests.') +parser.add_argument( + '--python-libdir', + type=str, + default=None, + help='Optional location of the in-tree module lib directory.') +parser.add_argument( + '--parallel', + action="store_true", + default=False, + help='Ignored. For compatibility with run-tests.scm.') args = parser.parse_args() if not args.interpreters: args.interpreters = [sys.executable] out = sys.stdout if args.verbose else None err = sys.stderr if args.verbose else None + def status_to_str(code): return {0: "PASS", 77: "SKIP", 99: "ERROR"}.get(code, "FAIL") + results = list() for interpreter in args.interpreters: - version = subprocess.check_output( - [interpreter, "-c", "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"]).strip().decode() + version = subprocess.check_output([ + interpreter, "-c", + "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" + ]).strip().decode() if args.python_libdir: python_libdir = args.python_libdir else: - pattern = os.path.join(args.builddir, "..", - "{0}-gpg".format(os.path.basename(interpreter)), - "lib*") + pattern = os.path.join(args.builddir, "..", "{0}-gpg".format( + os.path.basename(interpreter)), "lib*") libdirs = glob.glob(pattern) if len(libdirs) == 0: - sys.exit("Build directory matching {0!r} not found.".format(pattern)) + sys.exit( + "Build directory matching {0!r} not found.".format(pattern)) elif len(libdirs) > 1: - sys.exit("Multiple build directories matching {0!r} found: {1}".format( - pattern, libdirs)) + sys.exit( + "Multiple build directories matching {0!r} found: {1}".format( + pattern, libdirs)) python_libdir = libdirs[0] env = dict(os.environ) env["PYTHONPATH"] = python_libdir if not args.quiet: print("Running tests using {0} ({1})...".format(interpreter, version)) for test in args.tests: status = subprocess.call( [interpreter, os.path.join(args.srcdir, test)], - env=env, stdout=out, stderr=err) + env=env, + stdout=out, + stderr=err) if not args.quiet: print("{0}: {1}".format(status_to_str(status), test)) results.append(status) + def count(status): return len(list(filter(lambda x: x == status, results))) + + def failed(): return len(list(filter(lambda x: x not in (0, 77, 99), results))) + if not args.quiet: print("{0} tests run, {1} succeeded, {2} failed, {3} skipped.".format( len(results), count(0), failed(), count(77))) sys.exit(len(results) - count(0) - count(77)) sys.exit(results[0]) diff --git a/lang/python/tests/support.py b/lang/python/tests/support.py index efccf315..e6b3d8bb 100644 --- a/lang/python/tests/support.py +++ b/lang/python/tests/support.py @@ -1,133 +1,150 @@ # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import contextlib import shutil import sys import os import re import tempfile import time import gpg +del absolute_import, print_function, unicode_literals + + def assert_gpg_version(version=(2, 1, 0)): with gpg.Context() as c: - clean_version = re.match(r'\d+\.\d+\.\d+', c.engine_info.version).group(0) + clean_version = re.match(r'\d+\.\d+\.\d+', + c.engine_info.version).group(0) if tuple(map(int, clean_version.split('.'))) < version: print("GnuPG too old: have {0}, need {1}.".format( c.engine_info.version, '.'.join(map(str, version)))) sys.exit(77) + def have_tofu_support(ctx, some_uid): - keys = list(ctx.keylist(some_uid, - mode=(gpg.constants.keylist.mode.LOCAL - |gpg.constants.keylist.mode.WITH_TOFU))) + keys = list( + ctx.keylist( + some_uid, + mode=(gpg.constants.keylist.mode.LOCAL | + gpg.constants.keylist.mode.WITH_TOFU))) return len(keys) > 0 + # Skip the Python tests for GnuPG < 2.1.12. Prior versions do not # understand the command line flags that we assume exist. C.f. issue # 3008. assert_gpg_version((2, 1, 12)) # known keys alpha = "A0FF4590BB6122EDEF6E3C542D727CC768697734" bob = "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2" encrypt_only = "F52770D5C4DB41408D918C9F920572769B9FE19C" sign_only = "7CCA20CCDE5394CEE71C9F0BFED153F12F18F45D" no_such_key = "A" * 40 + def make_filename(name): return os.path.join(os.environ['top_srcdir'], 'tests', 'gpg', name) + def in_srcdir(name): return os.path.join(os.environ['srcdir'], name) + verbose = int(os.environ.get('verbose', 0)) > 1 + + def print_data(data): if verbose: try: # See if it is a file-like object. data.seek(0, os.SEEK_SET) data = data.read() except: # Hope for the best. pass if hasattr(sys.stdout, "buffer"): sys.stdout.buffer.write(data) else: sys.stdout.write(data) + def mark_key_trusted(ctx, key): class Editor(object): def __init__(self): self.steps = ["trust", "save"] + def edit(self, status, args, out): if args == "keyedit.prompt": result = self.steps.pop(0) elif args == "edit_ownertrust.value": result = "5" elif args == "edit_ownertrust.set_ultimate.okay": result = "Y" elif args == "keyedit.save.okay": result = "Y" else: result = None return result + with gpg.Data() as sink: ctx.op_edit(key, Editor().edit, sink, sink) # Python3.2 and up has tempfile.TemporaryDirectory, but we cannot use # that, because there shutil.rmtree is used without # ignore_errors=True, and that races against gpg-agent deleting its # sockets. class TemporaryDirectory(object): def __enter__(self): self.path = tempfile.mkdtemp() return self.path + def __exit__(self, *args): shutil.rmtree(self.path, ignore_errors=True) + @contextlib.contextmanager def EphemeralContext(): with TemporaryDirectory() as tmp: home = os.environ['GNUPGHOME'] shutil.copy(os.path.join(home, "gpg.conf"), tmp) shutil.copy(os.path.join(home, "gpg-agent.conf"), tmp) with gpg.Context(home_dir=tmp) as ctx: yield ctx # Ask the agent to quit. agent_socket = os.path.join(tmp, "S.gpg-agent") ctx.protocol = gpg.constants.protocol.ASSUAN ctx.set_engine_info(ctx.protocol, file_name=agent_socket) try: ctx.assuan_transact(["KILLAGENT"]) except gpg.errors.GPGMEError as e: if e.getcode() == gpg.errors.ASS_CONNECT_FAILED: - pass # the agent was not running + pass # the agent was not running else: raise # Block until it is really gone. while os.path.exists(agent_socket): time.sleep(.01) diff --git a/lang/python/tests/t-callbacks.py b/lang/python/tests/t-callbacks.py index b311e3d4..25a1c238 100755 --- a/lang/python/tests/t-callbacks.py +++ b/lang/python/tests/t-callbacks.py @@ -1,256 +1,293 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals c = gpg.Context() c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) source = gpg.Data("Hallo Leute\n") sink = gpg.Data() # Valid passphrases, both as string and bytes. for passphrase in ('foo', b'foo'): + def passphrase_cb(hint, desc, prev_bad, hook=None): assert hook == passphrase return hook c.set_passphrase_cb(passphrase_cb, passphrase) c.op_encrypt([], 0, source, sink) + # Returning an invalid type. def passphrase_cb(hint, desc, prev_bad, hook=None): return 0 + c.set_passphrase_cb(passphrase_cb, None) try: c.op_encrypt([], 0, source, sink) except Exception as e: assert type(e) == TypeError assert str(e) == "expected str or bytes from passphrase callback, got int" else: assert False, "Expected an error, got none" # Raising an exception inside callback. myException = Exception() + + def passphrase_cb(hint, desc, prev_bad, hook=None): raise myException + c.set_passphrase_cb(passphrase_cb, None) try: c.op_encrypt([], 0, source, sink) except Exception as e: assert e == myException else: assert False, "Expected an error, got none" + # Wrong kind of callback function. def bad_passphrase_cb(): pass + c.set_passphrase_cb(bad_passphrase_cb, None) try: c.op_encrypt([], 0, source, sink) except Exception as e: assert type(e) == TypeError else: assert False, "Expected an error, got none" - - # Test the progress callback. parms = """ Key-Type: RSA Key-Length: 1024 Name-Real: Joe Tester Name-Comment: with stupid passphrase Name-Email: joe+gpg@example.org Passphrase: Crypt0R0cks Expire-Date: 2099-12-31 """ messages = [] + + def progress_cb(what, typ, current, total, hook=None): assert hook == messages messages.append( "PROGRESS UPDATE: what = {}, type = {}, current = {}, total = {}" .format(what, typ, current, total)) + c = gpg.Context() c.set_progress_cb(progress_cb, messages) c.op_genkey(parms, None, None) assert len(messages) > 0 + # Test exception handling. def progress_cb(what, typ, current, total, hook=None): raise myException + c = gpg.Context() c.set_progress_cb(progress_cb, None) try: c.op_genkey(parms, None, None) except Exception as e: assert e == myException else: assert False, "Expected an error, got none" - # Test the edit callback. c = gpg.Context() c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) c.set_passphrase_cb(lambda *args: "abc") sink = gpg.Data() alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) cookie = object() edit_cb_called = False + + def edit_cb(status, args, hook): global edit_cb_called edit_cb_called = True assert hook == cookie return "quit" if args == "keyedit.prompt" else None + + c.op_edit(alpha, edit_cb, cookie, sink) assert edit_cb_called # Test exceptions. c = gpg.Context() c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) c.set_passphrase_cb(lambda *args: "abc") sink = gpg.Data() + def edit_cb(status, args): raise myException + + try: c.op_edit(alpha, edit_cb, None, sink) except Exception as e: assert e == myException else: assert False, "Expected an error, got none" - - # Test the status callback. source = gpg.Data("Hallo Leute\n") sink = gpg.Data() status_cb_called = False + + def status_cb(keyword, args, hook=None): global status_cb_called status_cb_called = True assert hook == cookie + c = gpg.Context() c.set_status_cb(status_cb, cookie) c.set_ctx_flag("full-status", "1") c.op_encrypt([alpha], gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) assert status_cb_called # Test exceptions. source = gpg.Data("Hallo Leute\n") sink = gpg.Data() + def status_cb(keyword, args): raise myException + c = gpg.Context() c.set_status_cb(status_cb, None) c.set_ctx_flag("full-status", "1") try: c.op_encrypt([alpha], gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) except Exception as e: assert e == myException else: assert False, "Expected an error, got none" - # Test the data callbacks. def read_cb(amount, hook=None): assert hook == cookie return 0 + + def release_cb(hook=None): assert hook == cookie + + data = gpg.Data(cbs=(read_cb, None, None, release_cb, cookie)) try: data.read() except Exception as e: assert type(e) == TypeError else: assert False, "Expected an error, got none" + def read_cb(amount): raise myException + + data = gpg.Data(cbs=(read_cb, None, None, lambda: None)) try: data.read() except Exception as e: assert e == myException else: assert False, "Expected an error, got none" def write_cb(what, hook=None): assert hook == cookie return "wrong type" + + data = gpg.Data(cbs=(None, write_cb, None, release_cb, cookie)) try: data.write(b'stuff') except Exception as e: assert type(e) == TypeError else: assert False, "Expected an error, got none" + def write_cb(what): raise myException + + data = gpg.Data(cbs=(None, write_cb, None, lambda: None)) try: data.write(b'stuff') except Exception as e: assert e == myException else: assert False, "Expected an error, got none" def seek_cb(offset, whence, hook=None): assert hook == cookie return "wrong type" + + data = gpg.Data(cbs=(None, None, seek_cb, release_cb, cookie)) try: data.seek(0, os.SEEK_SET) except Exception as e: assert type(e) == TypeError else: assert False, "Expected an error, got none" + def seek_cb(offset, whence): raise myException + + data = gpg.Data(cbs=(None, None, seek_cb, lambda: None)) try: data.seek(0, os.SEEK_SET) except Exception as e: assert e == myException else: assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-data.py b/lang/python/tests/t-data.py index 5cf074c5..006c11f4 100755 --- a/lang/python/tests/t-data.py +++ b/lang/python/tests/t-data.py @@ -1,137 +1,140 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import io import os import tempfile import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals data = gpg.Data('Hello world!') assert data.read() == b'Hello world!' assert data.read() == b'' data.seek(0, os.SEEK_SET) assert data.read() == b'Hello world!' assert data.read() == b'' data = gpg.Data(b'Hello world!') assert data.read() == b'Hello world!' data = gpg.Data(b'Hello world!', copy=False) assert data.read() == b'Hello world!' data = gpg.Data() data.write('Hello world!') data.seek(0, os.SEEK_SET) assert data.read() == b'Hello world!' data = gpg.Data() data.write(b'Hello world!') data.seek(0, os.SEEK_SET) assert data.read() == b'Hello world!' data = gpg.Data() data.write(b'Hello world!') # We expect the second argument to default to SEEK_SET data.seek(0) assert data.read() == b'Hello world!' binjunk = bytes(range(256)) data = gpg.Data() data.write(binjunk) data.seek(0, os.SEEK_SET) assert data.read() == binjunk data = gpg.Data() data.set_file_name("foobar") assert data.get_file_name() == "foobar" # Test reading from an existing file. with tempfile.NamedTemporaryFile() as tmp: tmp.write(binjunk) tmp.flush() tmp.seek(0) # Open using name. data = gpg.Data(file=tmp.name) assert data.read() == binjunk # Open using name, without copying. if False: # delayed reads are not yet supported data = gpg.Data(file=tmp.name, copy=False) assert data.read() == binjunk # Open using stream. tmp.seek(0) data = gpg.Data(file=tmp) assert data.read() == binjunk # Open using stream, offset, and length. data = gpg.Data(file=tmp, offset=0, length=42) assert data.read() == binjunk[:42] # Open using name, offset, and length. data = gpg.Data(file=tmp.name, offset=23, length=42) - assert data.read() == binjunk[23:23+42] + assert data.read() == binjunk[23:23 + 42] + # Test callbacks. class DataObject(object): def __init__(self): self.buffer = io.BytesIO() self.released = False def read(self, amount, hook=None): assert not self.released return self.buffer.read(amount) def write(self, data, hook=None): assert not self.released return self.buffer.write(data) def seek(self, offset, whence, hook=None): assert not self.released return self.buffer.seek(offset, whence) def release(self, hook=None): assert not self.released self.released = True + do = DataObject() cookie = object() data = gpg.Data(cbs=(do.read, do.write, do.seek, do.release, cookie)) data.write('Hello world!') data.seek(0, os.SEEK_SET) assert data.read() == b'Hello world!' del data assert do.released # Again, without the cookie. do = DataObject() data = gpg.Data(cbs=(do.read, do.write, do.seek, do.release)) data.write('Hello world!') data.seek(0, os.SEEK_SET) assert data.read() == b'Hello world!' del data assert do.released diff --git a/lang/python/tests/t-decrypt-verify.py b/lang/python/tests/t-decrypt-verify.py index 03bbc4b5..fcaa1346 100755 --- a/lang/python/tests/t-decrypt-verify.py +++ b/lang/python/tests/t-decrypt-verify.py @@ -1,75 +1,77 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + + def check_verify_result(result, summary, fpr, status): assert len(result.signatures) == 1, "Unexpected number of signatures" sig = result.signatures[0] assert sig.summary == summary, "Unexpected signature summary" assert sig.fpr == fpr assert gpg.errors.GPGMEError(sig.status).getcode() == status assert len(sig.notations) == 0 assert not sig.wrong_key_usage assert sig.validity == gpg.constants.validity.FULL - assert gpg.errors.GPGMEError(sig.validity_reason).getcode() == gpg.errors.NO_ERROR + assert gpg.errors.GPGMEError( + sig.validity_reason).getcode() == gpg.errors.NO_ERROR + c = gpg.Context() source = gpg.Data(file=support.make_filename("cipher-2.asc")) sink = gpg.Data() c.op_decrypt_verify(source, sink) result = c.op_decrypt_result() assert not result.unsupported_algorithm, \ "Unsupported algorithm: {}".format(result.unsupported_algorithm) support.print_data(sink) verify_result = c.op_verify_result() -check_verify_result(verify_result, - gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR) +check_verify_result( + verify_result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR) # Idiomatic interface. with gpg.Context() as c: alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) plaintext, _, verify_result = \ c.decrypt(open(support.make_filename("cipher-2.asc")), verify=[alpha]) assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ 'Plaintext not found' - check_verify_result(verify_result, - gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR) + check_verify_result( + verify_result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR) try: - c.decrypt(open(support.make_filename("cipher-2.asc")), - verify=[alpha, bob]) + c.decrypt( + open(support.make_filename("cipher-2.asc")), verify=[alpha, bob]) except gpg.errors.MissingSignatures as e: assert len(e.missing) == 1 assert e.missing[0] == bob else: assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-decrypt.py b/lang/python/tests/t-decrypt.py index 05b6d8b0..f2417c9a 100755 --- a/lang/python/tests/t-decrypt.py +++ b/lang/python/tests/t-decrypt.py @@ -1,43 +1,44 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + c = gpg.Context() source = gpg.Data(file=support.make_filename("cipher-1.asc")) sink = gpg.Data() c.op_decrypt(source, sink) result = c.op_decrypt_result() assert not result.unsupported_algorithm, \ "Unsupported algorithm: {}".format(result.unsupported_algorithm) support.print_data(sink) # Idiomatic interface. with gpg.Context() as c: plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc"))) assert len(plaintext) > 0 assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ 'Plaintext not found' diff --git a/lang/python/tests/t-edit.py b/lang/python/tests/t-edit.py index b1075a96..cbc17d95 100755 --- a/lang/python/tests/t-edit.py +++ b/lang/python/tests/t-edit.py @@ -1,71 +1,76 @@ #!/usr/bin/env python # Copyright (C) 2005 Igor Belyi # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import sys import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals + class KeyEditor(object): def __init__(self): self.steps = ["fpr", "expire", "1", "primary", "quit"] self.step = 0 self.done = False self.verbose = int(os.environ.get('verbose', 0)) > 1 def edit_fnc(self, status, args, out=None): if args == "keyedit.prompt": result = self.steps[self.step] self.step += 1 elif args == "keyedit.save.okay": result = "Y" self.done = self.step == len(self.steps) elif args == "keygen.valid": result = "0" else: result = None if self.verbose: - sys.stderr.write("Code: {}, args: {!r}, Returning: {!r}\n" - .format(status, args, result)) + sys.stderr.write("Code: {}, args: {!r}, Returning: {!r}\n".format( + status, args, result)) return result + c = gpg.Context() c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) c.set_passphrase_cb(lambda *args: "abc") c.set_armor(True) # The deprecated interface. editor = KeyEditor() -c.interact(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), - editor.edit_fnc) +c.interact( + c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), + editor.edit_fnc) assert editor.done # The deprecated interface. sink = gpg.Data() editor = KeyEditor() -c.op_edit(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), - editor.edit_fnc, sink, sink) +c.op_edit( + c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False), + editor.edit_fnc, sink, sink) assert editor.done diff --git a/lang/python/tests/t-encrypt-large.py b/lang/python/tests/t-encrypt-large.py index 56460851..18576ac3 100755 --- a/lang/python/tests/t-encrypt-large.py +++ b/lang/python/tests/t-encrypt-large.py @@ -1,65 +1,72 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import sys import random import gpg import support +del absolute_import, print_function, unicode_literals + if len(sys.argv) == 2: nbytes = int(sys.argv[1]) else: nbytes = 100000 c = gpg.Context() ntoread = nbytes + + def read_cb(amount): global ntoread chunk = ntoread if ntoread < amount else amount ntoread -= chunk assert ntoread >= 0 assert chunk >= 0 return bytes(bytearray(random.randrange(256) for i in range(chunk))) + nwritten = 0 + + def write_cb(data): global nwritten nwritten += len(data) return len(data) + source = gpg.Data(cbs=(read_cb, None, None, lambda: None)) sink = gpg.Data(cbs=(None, write_cb, None, lambda: None)) keys = [] keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) result = c.op_encrypt_result() assert not result.invalid_recipients, \ "Invalid recipient encountered: {}".format(result.invalid_recipients.fpr) assert ntoread == 0 if support.verbose: - sys.stderr.write( - "plaintext={} bytes, ciphertext={} bytes\n".format(nbytes, nwritten)) + sys.stderr.write("plaintext={} bytes, ciphertext={} bytes\n".format( + nbytes, nwritten)) diff --git a/lang/python/tests/t-encrypt-sign.py b/lang/python/tests/t-encrypt-sign.py index f04783f4..84d1abb4 100755 --- a/lang/python/tests/t-encrypt-sign.py +++ b/lang/python/tests/t-encrypt-sign.py @@ -1,96 +1,99 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import sys import gpg import support +del absolute_import, print_function, unicode_literals + c = gpg.Context() c.set_armor(True) + def check_result(r, typ): if r.invalid_signers: sys.exit("Invalid signer found: {}".format(r.invalid_signers.fpr)) if len(r.signatures) != 1: sys.exit("Unexpected number of signatures created") signature = r.signatures[0] if signature.type != typ: sys.exit("Wrong type of signature created") if signature.pubkey_algo != gpg.constants.pk.DSA: sys.exit("Wrong pubkey algorithm reported: {}".format( signature.pubkey_algo)) - if signature.hash_algo not in (gpg.constants.md.SHA1, gpg.constants.md.RMD160): + if signature.hash_algo not in (gpg.constants.md.SHA1, + gpg.constants.md.RMD160): sys.exit("Wrong hash algorithm reported: {}".format( signature.hash_algo)) if signature.sig_class != 0: sys.exit("Wrong signature class reported: {}".format( signature.sig_class)) if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734": sys.exit("Wrong fingerprint reported: {}".format(signature.fpr)) + keys = [] keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) for recipients in (keys, []): source = gpg.Data("Hallo Leute\n") sink = gpg.Data() - c.op_encrypt_sign(recipients, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) + c.op_encrypt_sign(recipients, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, + sink) result = c.op_encrypt_result() assert not result.invalid_recipients, \ "Invalid recipient encountered: {}".format( result.invalid_recipients.fpr) result = c.op_sign_result() check_result(result, gpg.constants.sig.mode.NORMAL) support.print_data(sink) - # Idiomatic interface. with gpg.Context(armor=True) as c: message = "Hallo Leute\n".encode() - ciphertext, _, sig_result = c.encrypt(message, - recipients=keys, - always_trust=True) + ciphertext, _, sig_result = c.encrypt( + message, recipients=keys, always_trust=True) assert len(ciphertext) > 0 assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' check_result(sig_result, gpg.constants.sig.mode.NORMAL) c.signers = [c.get_key(support.sign_only, True)] c.encrypt(message, recipients=keys, always_trust=True) c.signers = [c.get_key(support.encrypt_only, True)] try: c.encrypt(message, recipients=keys, always_trust=True) except gpg.errors.InvalidSigners as e: assert len(e.signers) == 1 assert support.encrypt_only.endswith(e.signers[0].fpr) else: assert False, "Expected an InvalidSigners error, got none" diff --git a/lang/python/tests/t-encrypt-sym.py b/lang/python/tests/t-encrypt-sym.py index 82992934..9b099fe0 100755 --- a/lang/python/tests/t-encrypt-sym.py +++ b/lang/python/tests/t-encrypt-sym.py @@ -1,84 +1,86 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals for passphrase in ("abc", b"abc"): c = gpg.Context() c.set_armor(True) c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) source = gpg.Data("Hallo Leute\n") cipher = gpg.Data() passphrase_cb_called = 0 + def passphrase_cb(hint, desc, prev_bad, hook=None): global passphrase_cb_called passphrase_cb_called += 1 return passphrase c.set_passphrase_cb(passphrase_cb, None) c.op_encrypt([], 0, source, cipher) assert passphrase_cb_called == 1, \ "Callback called {} times".format(passphrase_cb_called) support.print_data(cipher) c = gpg.Context() c.set_armor(True) c.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK) c.set_passphrase_cb(passphrase_cb, None) plain = gpg.Data() cipher.seek(0, os.SEEK_SET) c.op_decrypt(cipher, plain) # Seems like the passphrase is cached. - #assert passphrase_cb_called == 2, \ + # assert passphrase_cb_called == 2, \ # "Callback called {} times".format(passphrase_cb_called) support.print_data(plain) plain.seek(0, os.SEEK_SET) plaintext = plain.read() assert plaintext == b"Hallo Leute\n", \ "Wrong plaintext {!r}".format(plaintext) # Idiomatic interface. for passphrase in ("abc", b"abc"): with gpg.Context(armor=True) as c: # Check that the passphrase callback is not altered. def f(*args): assert False + c.set_passphrase_cb(f) message = "Hallo Leute\n".encode() - ciphertext, _, _ = c.encrypt(message, - passphrase=passphrase, - sign=False) + ciphertext, _, _ = c.encrypt( + message, passphrase=passphrase, sign=False) assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' plaintext, _, _ = c.decrypt(ciphertext, passphrase=passphrase) assert plaintext == message, 'Message body not recovered' assert c._passphrase_cb[1] == f, "Passphrase callback not restored" diff --git a/lang/python/tests/t-encrypt.py b/lang/python/tests/t-encrypt.py index 921502a7..e702daa6 100755 --- a/lang/python/tests/t-encrypt.py +++ b/lang/python/tests/t-encrypt.py @@ -1,78 +1,80 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + c = gpg.Context() c.set_armor(True) source = gpg.Data("Hallo Leute\n") sink = gpg.Data() keys = [] keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)) c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, sink) result = c.op_encrypt_result() assert not result.invalid_recipients, \ "Invalid recipients: {}".format(", ".join(r.fpr for r in result.recipients)) support.print_data(sink) # Idiomatic interface. with gpg.Context(armor=True) as c: - ciphertext, _, _ = c.encrypt("Hallo Leute\n".encode(), - recipients=keys, - sign=False, - always_trust=True) + ciphertext, _, _ = c.encrypt( + "Hallo Leute\n".encode(), + recipients=keys, + sign=False, + always_trust=True) assert len(ciphertext) > 0 assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found' - c.encrypt("Hallo Leute\n".encode(), - recipients=[c.get_key(support.encrypt_only, False)], - sign=False, always_trust=True) + c.encrypt( + "Hallo Leute\n".encode(), + recipients=[c.get_key(support.encrypt_only, False)], + sign=False, + always_trust=True) try: - c.encrypt("Hallo Leute\n".encode(), - recipients=[c.get_key(support.sign_only, False)], - sign=False, always_trust=True) + c.encrypt( + "Hallo Leute\n".encode(), + recipients=[c.get_key(support.sign_only, False)], + sign=False, + always_trust=True) except gpg.errors.InvalidRecipients as e: assert len(e.recipients) == 1 assert support.sign_only.endswith(e.recipients[0].fpr) else: assert False, "Expected an InvalidRecipients error, got none" - - try: # People might be tempted to provide strings. # We should raise something useful. - ciphertext, _, _ = c.encrypt("Hallo Leute\n", - recipients=keys, - sign=False, - always_trust=True) + ciphertext, _, _ = c.encrypt( + "Hallo Leute\n", recipients=keys, sign=False, always_trust=True) except TypeError as e: # This test is a bit fragile, because the message # may very well change. So if the behaviour will change # this test can easily be deleted. assert "encode" in str(e) diff --git a/lang/python/tests/t-export.py b/lang/python/tests/t-export.py index b9d52048..6d771dd4 100755 --- a/lang/python/tests/t-export.py +++ b/lang/python/tests/t-export.py @@ -1,39 +1,40 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + c = gpg.Context() c.set_armor(True) sink = gpg.Data() c.op_export_ext(['Alpha', 'Bob'], 0, sink) support.print_data(sink) # Again. Now using a key array. keys = [] -keys.append(c.get_key("0x68697734", False)) # Alpha -keys.append(c.get_key("0xA9E3B0B2", False)) # Bob +keys.append(c.get_key("0x68697734", False)) # Alpha +keys.append(c.get_key("0xA9E3B0B2", False)) # Bob sink = gpg.Data() c.op_export_keys(keys, 0, sink) support.print_data(sink) diff --git a/lang/python/tests/t-file-name.py b/lang/python/tests/t-file-name.py index 32fe84a0..d9c226fa 100755 --- a/lang/python/tests/t-file-name.py +++ b/lang/python/tests/t-file-name.py @@ -1,45 +1,46 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals testname = "abcde12345" c = gpg.Context() c.set_armor(True) source = gpg.Data("Hallo Leute\n") source.set_file_name(testname) cipher = gpg.Data() plain = gpg.Data() keys = [] keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)) c.op_encrypt(keys, gpg.constants.ENCRYPT_ALWAYS_TRUST, source, cipher) cipher.seek(0, os.SEEK_SET) c.op_decrypt(cipher, plain) result = c.op_decrypt_result() assert result.file_name == testname diff --git a/lang/python/tests/t-idiomatic.py b/lang/python/tests/t-idiomatic.py index b7ae4eb9..238bbf31 100755 --- a/lang/python/tests/t-idiomatic.py +++ b/lang/python/tests/t-idiomatic.py @@ -1,83 +1,86 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import sys import io import os import tempfile import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals # Both Context and Data can be used as context manager: with gpg.Context() as c, gpg.Data() as d: c.get_engine_info() d.write(b"Halloechen") leak_c = c leak_d = d -assert leak_c.wrapped == None -assert leak_d.wrapped == None +assert leak_c.wrapped is None +assert leak_d.wrapped is None + def sign_and_verify(source, signed, sink): with gpg.Context() as c: c.op_sign(source, signed, gpg.constants.sig.mode.NORMAL) signed.seek(0, os.SEEK_SET) c.op_verify(signed, None, sink) result = c.op_verify_result() assert len(result.signatures) == 1, "Unexpected number of signatures" sig = result.signatures[0] assert sig.summary == (gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN) assert gpg.errors.GPGMEError(sig.status).getcode() == gpg.errors.NO_ERROR sink.seek(0, os.SEEK_SET) assert sink.read() == b"Hallo Leute\n" + # Demonstrate automatic wrapping of file-like objects with 'fileno' # method. with tempfile.TemporaryFile() as source, \ tempfile.TemporaryFile() as signed, \ tempfile.TemporaryFile() as sink: source.write(b"Hallo Leute\n") source.seek(0, os.SEEK_SET) sign_and_verify(source, signed, sink) if sys.version_info[0] == 3: # Python2's io.BytesIO does not implement the buffer interface, # hence we cannot use it as sink. # XXX: Python's io.BytesIo.truncate does not work as advertised. # http://bugs.python.org/issue27261 bio = io.BytesIO() bio.truncate(1) if len(bio.getvalue()) != 1: # This version of Python is affected, preallocate buffer. - preallocate = 128*b'\x00' + preallocate = 128 * b'\x00' else: preallocate = b'' # Demonstrate automatic wrapping of objects implementing the buffer # interface, and the use of data objects with the 'with' statement. with io.BytesIO(preallocate) as signed, gpg.Data() as sink: sign_and_verify(b"Hallo Leute\n", signed, sink) diff --git a/lang/python/tests/t-import.py b/lang/python/tests/t-import.py index 44dc360b..8d8a6998 100755 --- a/lang/python/tests/t-import.py +++ b/lang/python/tests/t-import.py @@ -1,82 +1,85 @@ #!/usr/bin/env python # Copyright (C) 2016 Tobias Mueller # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + + def check_result(result, fpr, secret): assert result.considered == 1 or (secret and result.considered == 3) assert result.no_user_id == 0 - assert not ((secret and result.imported != 0) - or (not secret and (result.imported != 0 - and result.imported != 1))) + assert not ((secret and result.imported != 0) or + (not secret and + (result.imported != 0 and result.imported != 1))) assert result.imported_rsa == 0 - assert not ((secret and (result.unchanged != 0 and result.unchanged != 1)) - or (not secret and ((result.imported == 0 - and result.unchanged != 1) - or (result.imported == 1 - and result.unchanged != 0)))) + assert not ((secret and + (result.unchanged != 0 and result.unchanged != 1)) or + (not secret and + ((result.imported == 0 and result.unchanged != 1) or + (result.imported == 1 and result.unchanged != 0)))) assert result.new_user_ids == 0 assert result.new_sub_keys == 0 - assert not ((secret - and ((result.secret_imported == 0 - and result.new_signatures != 0) - or (result.secret_imported == 1 - and result.new_signatures > 1))) - or (not secret and result.new_signatures != 0)) + assert not ((secret and ( + (result.secret_imported == 0 and result.new_signatures != 0) or + (result.secret_imported == 1 and result.new_signatures > 1))) or + (not secret and result.new_signatures != 0)) assert result.new_revocations == 0 - assert not ((secret and result.secret_read != 1 and result.secret_read != 3) - or (not secret and result.secret_read != 0)) - assert not ((secret and result.secret_imported != 0 - and result.secret_imported != 1 - and result.secret_imported != 2) - or (not secret and result.secret_imported != 0)) - assert not ((secret - and ((result.secret_imported == 0 - and result.secret_unchanged != 1 - and result.secret_unchanged != 2) - or (result.secret_imported == 1 - and result.secret_unchanged != 0))) - or (not secret and result.secret_unchanged != 0)) + assert not ( + (secret and result.secret_read != 1 and result.secret_read != 3) or + (not secret and result.secret_read != 0)) + assert not ( + (secret and result.secret_imported != 0 and result. + secret_imported != 1 and result. + secret_imported != 2) or (not secret and result. + secret_imported != 0)) + assert not ((secret and + ((result.secret_imported == 0 and result. + secret_unchanged != 1 and result. + secret_unchanged != 2) or (result. + secret_imported == 1 and result. + secret_unchanged != 0))) or + (not secret and result.secret_unchanged != 0)) assert result.not_imported == 0 if secret: assert not (len(result.imports) in (0, 3)) else: assert not (len(result.imports) in (0, 2)) assert fpr == result.imports[0].fpr assert len(result.imports) == 1 or fpr == result.imports[1].fpr assert result.imports[0].result == 0 + c = gpg.Context() result = c.key_import(open(support.make_filename("pubkey-1.asc"), 'rb').read()) check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", False) result = c.key_import(open(support.make_filename("seckey-1.asc"), 'rb').read()) check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", True) try: result = c.key_import(b"thisisnotakey") except ValueError: pass assert result.considered == 0 diff --git a/lang/python/tests/t-keylist-from-data.py b/lang/python/tests/t-keylist-from-data.py index 6503eb7a..f82ca842 100755 --- a/lang/python/tests/t-keylist-from-data.py +++ b/lang/python/tests/t-keylist-from-data.py @@ -1,211 +1,267 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + support.assert_gpg_version((2, 1, 14)) + # Check expration of keys. This test assumes three subkeys of which # 2 are expired; it is used with the "Whisky" test key. It has # already been checked that these 3 subkeys are available. def check_whisky(name, key): - sub1 = key.subkeys[2] - sub2 = key.subkeys[3] + sub1 = key.subkeys[2] + sub2 = key.subkeys[3] + + assert sub1.expired and sub2.expired, \ + "Subkey of `{}' not flagged as expired".format(name) + assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \ + "Subkey of `{}' has wrong expiration date".format(name) - assert sub1.expired and sub2.expired, \ - "Subkey of `{}' not flagged as expired".format(name) - assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \ - "Subkey of `{}' has wrong expiration date".format(name) keys = [ - [ "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8", - [ [ "Alfa Test", "demo key", "alfa@example.net" ], - [ "Alpha Test", "demo key", "alpha@example.net" ], - [ "Alice", "demo key", "" ] ], 1 ], - [ "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F", - [ [ "Bob", "demo key", "" ], - [ "Bravo Test", "demo key", "bravo@example.net" ] ], 1 ], - [ "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60", - [ [ "Charlie Test", "demo key", "charlie@example.net" ] ], 1 ], - [ "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424", - [ [ "Delta Test", "demo key", "delta@example.net" ] ], 1 ], - [ "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D", - [ [ "Echelon", "demo key", "" ], - [ "Echo Test", "demo key", "echo@example.net" ], - [ "Eve", "demo key", "" ] ], 1 ], - [ "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E", - [ [ "Foxtrot Test", "demo key", "foxtrot@example.net" ] ], 1 ], - [ "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354", - [ [ "Golf Test", "demo key", "golf@example.net" ] ], 1 ], - [ "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A", - [ [ "Hotel Test", "demo key", "hotel@example.net" ] ], 1 ], - [ "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73", - [ [ "India Test", "demo key", "india@example.net" ] ], 1 ], - [ "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136", - [ [ "Juliet Test", "demo key", "juliet@example.net" ] ], 1 ], - [ "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02", - [ [ "Kilo Test", "demo key", "kilo@example.net" ] ], 1 ], - [ "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C", - [ [ "Lima Test", "demo key", "lima@example.net" ] ], 1 ], - [ "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8", - [ [ "Mallory", "demo key", "" ], - [ "Mike Test", "demo key", "mike@example.net" ] ], 1 ], - [ "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472", - [ [ "November Test", "demo key", "november@example.net" ] ], 1 ], - [ "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F", - [ [ "Oscar Test", "demo key", "oscar@example.net" ] ], 1 ], - [ "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C", - [ [ "Papa test", "demo key", "papa@example.net" ] ], 1 ], - [ "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4", - [ [ "Quebec Test", "demo key", "quebec@example.net" ] ], 1 ], - [ "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA", - [ [ "Romeo Test", "demo key", "romeo@example.net" ] ], 1 ], - [ "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4", - [ [ "Sierra Test", "demo key", "sierra@example.net" ] ], 1 ], - [ "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402", - [ [ "Tango Test", "demo key", "tango@example.net" ] ], 1 ], - [ "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9", - [ [ "Uniform Test", "demo key", "uniform@example.net" ] ], 1 ], - [ "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134", - [ [ "Victor Test", "demo key", "victor@example.org" ] ], 1 ], - [ "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6", - [ [ "Whisky Test", "demo key", "whisky@example.net" ] ], 3, - check_whisky ], - [ "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE", - [ [ "XRay Test", "demo key", "xray@example.net" ] ], 1 ], - [ "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD", - [ [ "Yankee Test", "demo key", "yankee@example.net" ] ], 1 ], - [ "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881", - [ [ "Zulu Test", "demo key", "zulu@example.net" ] ], 1 ], + [ + "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8", + [["Alfa Test", "demo key", "alfa@example.net"], + ["Alpha Test", "demo key", "alpha@example.net"], + ["Alice", "demo key", ""]], 1 + ], + [ + "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F", + [["Bob", "demo key", ""], + ["Bravo Test", "demo key", "bravo@example.net"]], 1 + ], + [ + "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60", + [["Charlie Test", "demo key", "charlie@example.net"]], 1 + ], + [ + "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424", + [["Delta Test", "demo key", "delta@example.net"]], 1 + ], + [ + "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D", + [["Echelon", "demo key", + ""], ["Echo Test", "demo key", "echo@example.net"], + ["Eve", "demo key", ""]], 1 + ], + [ + "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E", + [["Foxtrot Test", "demo key", "foxtrot@example.net"]], 1 + ], + [ + "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354", + [["Golf Test", "demo key", "golf@example.net"]], 1 + ], + [ + "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A", + [["Hotel Test", "demo key", "hotel@example.net"]], 1 + ], + [ + "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73", + [["India Test", "demo key", "india@example.net"]], 1 + ], + [ + "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136", + [["Juliet Test", "demo key", "juliet@example.net"]], 1 + ], + [ + "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02", + [["Kilo Test", "demo key", "kilo@example.net"]], 1 + ], + [ + "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C", + [["Lima Test", "demo key", "lima@example.net"]], 1 + ], + [ + "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8", + [["Mallory", "demo key", ""], + ["Mike Test", "demo key", "mike@example.net"]], 1 + ], + [ + "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472", + [["November Test", "demo key", "november@example.net"]], 1 + ], + [ + "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F", + [["Oscar Test", "demo key", "oscar@example.net"]], 1 + ], + [ + "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C", + [["Papa test", "demo key", "papa@example.net"]], 1 + ], + [ + "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4", + [["Quebec Test", "demo key", "quebec@example.net"]], 1 + ], + [ + "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA", + [["Romeo Test", "demo key", "romeo@example.net"]], 1 + ], + [ + "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4", + [["Sierra Test", "demo key", "sierra@example.net"]], 1 + ], + [ + "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402", + [["Tango Test", "demo key", "tango@example.net"]], 1 + ], + [ + "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9", + [["Uniform Test", "demo key", "uniform@example.net"]], 1 + ], + [ + "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134", + [["Victor Test", "demo key", "victor@example.org"]], 1 + ], + [ + "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6", + [["Whisky Test", "demo key", "whisky@example.net"]], 3, check_whisky + ], + [ + "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE", + [["XRay Test", "demo key", "xray@example.net"]], 1 + ], + [ + "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD", + [["Yankee Test", "demo key", "yankee@example.net"]], 1 + ], + [ + "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881", + [["Zulu Test", "demo key", "zulu@example.net"]], 1 + ], ] + def check_global(key, uids, n_subkeys): assert not key.revoked, "Key unexpectedly revoked" assert not key.expired, "Key unexpectedly expired" assert not key.disabled, "Key unexpectedly disabled" assert not key.invalid, "Key unexpectedly invalid" assert key.can_sign, "Key unexpectedly unusable for signing" assert key.can_certify, "Key unexpectedly unusable for certifications" assert not key.secret, "Key unexpectedly secret" - assert not key.protocol != gpg.constants.protocol.OpenPGP, \ - "Key has unexpected protocol: {}".format(key.protocol) - assert not key.issuer_serial, \ - "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial) - assert not key.issuer_name, \ - "Key unexpectedly carries issuer name: {}".format(key.issuer_name) - assert not key.chain_id, \ - "Key unexpectedly carries chain ID: {}".format(key.chain_id) - assert key.owner_trust == gpg.constants.validity.UNKNOWN, \ - "Key has unexpected owner trust: {}".format(key.owner_trust) - assert len(key.subkeys) - 1 == n_subkeys, \ - "Key `{}' has unexpected number of subkeys".format(uids[0][0]) + assert not key.protocol != gpg.constants.protocol. + OpenPGP, "Key has unexpected protocol: {}".format(key.protocol) + assert not key.issuer_serial, + "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial) + assert not key.issuer_name, + "Key unexpectedly carries issuer name: {}".format(key.issuer_name) + assert not key.chain_id, + "Key unexpectedly carries chain ID: {}".format(key.chain_id) + assert key.owner_trust == gpg.constants.validity.UNKNOWN, + "Key has unexpected owner trust: {}".format(key.owner_trust) + assert len(key.subkeys) - 1 == n_subkeys, + "Key `{}' has unexpected number of subkeys".format(uids[0][0]) def check_subkey(fpr, which, subkey): assert not subkey.revoked, which + " key unexpectedly revoked" assert not subkey.expired, which + " key unexpectedly expired" assert not subkey.disabled, which + " key unexpectedly disabled" assert not subkey.invalid, which + " key unexpectedly invalid" if which == "Primary": - assert not subkey.can_encrypt, \ - which + " key unexpectedly usable for encryption" - assert subkey.can_sign, \ - which + " key unexpectedly unusable for signing" - assert subkey.can_certify, \ - which + " key unexpectedly unusable for certifications" + assert not subkey.can_encrypt, + which + " key unexpectedly usable for encryption" + assert subkey.can_sign, + which + " key unexpectedly unusable for signing" + assert subkey.can_certify, + which + " key unexpectedly unusable for certifications" else: - assert subkey.can_encrypt, \ - which + " key unexpectedly unusable for encryption" - assert not subkey.can_sign, \ - which + " key unexpectedly usable for signing" - assert not subkey.can_certify, \ - which + " key unexpectedly usable for certifications" + assert subkey.can_encrypt, + which + " key unexpectedly unusable for encryption" + assert not subkey.can_sign, + which + " key unexpectedly usable for signing" + assert not subkey.can_certify, + which + " key unexpectedly usable for certifications" assert not subkey.secret, which + " key unexpectedly secret" assert not subkey.is_cardkey, "Public key marked as card key" assert not subkey.card_number, "Public key with card number set" - assert not subkey.pubkey_algo != (gpg.constants.pk.DSA if which == "Primary" - else gpg.constants.pk.ELG_E), \ - which + " key has unexpected public key algo: {}".\ - format(subkey.pubkey_algo) - assert subkey.length == 1024, \ - which + " key has unexpected length: {}".format(subkey.length) - assert fpr.endswith(subkey.keyid), \ - which + " key has unexpected key ID: {}".format(subkey.keyid) - assert which == "Secondary" or subkey.fpr == fpr, \ - which + " key has unexpected fingerprint: {}".format(subkey.fpr) - assert not subkey.expires, \ - which + " key unexpectedly expires: {}".format(subkey.expires) + assert not subkey.pubkey_algo != + (gpg.constants.pk.DSA if which == "Primary" else gpg.constants.pk.ELG_E), + which + " key has unexpected public key algo: {}".format(subkey. + pubkey_algo) + assert subkey.length == 1024, + which + " key has unexpected length: {}".format(subkey.length) + assert fpr.endswith(subkey.keyid), + which + " key has unexpected key ID: {}".format(subkey.keyid) + assert which == "Secondary" or subkey.fpr == fpr, + which + " key has unexpected fingerprint: {}".format(subkey.fpr) + assert not subkey.expires, + which + " key unexpectedly expires: {}".format(subkey.expires) + def check_uid(which, ref, uid): assert not uid.revoked, which + " user ID unexpectedly revoked" assert not uid.invalid, which + " user ID unexpectedly invalid" - assert uid.validity == gpg.constants.validity.UNKNOWN, \ - which + " user ID has unexpected validity: {}".format(uid.validity) + assert uid.validity == gpg.constants.validity.UNKNOWN, + which + " user ID has unexpected validity: {}".format(uid.validity) assert not uid.signatures, which + " user ID unexpectedly signed" - assert uid.name == ref[0], \ - "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name) - assert uid.comment == ref[1], \ - "Unexpected comment in {} user ID: {!r}".format(which.lower(), - uid.comment) - assert uid.email == ref[2], \ - "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email) + assert uid.name == ref[0], + "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name) + assert uid.comment == ref[1], + "Unexpected comment in {} user ID: {!r}".format(which.lower(), uid.comment) + assert uid.email == ref[2], + "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email) + # Export all the data from our keyring... key_data = gpg.Data() with gpg.Context() as c: - c.op_export_keys([c.get_key(k[0]) for k in keys], 0, key_data) + c.op_export_keys([c.get_key(k[0]) for k in keys], 0, key_data) # ... rewind the tape... key_data.rewind() # ... and feed it into a keylist in an empty context. with support.EphemeralContext() as c: for i, key in enumerate(c.keylist(source=key_data)): try: if len(keys[i]) == 4: fpr, sec_keyid, uids, n_subkeys = keys[i] misc_check = None else: fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i] except IndexError: # There are more keys. We don't check for that. break # Global key flags. check_global(key, uids, n_subkeys) check_subkey(fpr, "Primary", key.subkeys[0]) check_subkey(sec_keyid, "Secondary", key.subkeys[1]) assert len(key.uids) == len(uids) check_uid("First", uids[0], key.uids[0]) if len(key.uids) > 1: - check_uid("Second", uids[1], key.uids[1]) + check_uid("Second", uids[1], key.uids[1]) if len(key.uids) > 2: - check_uid("Third", uids[2], key.uids[2]) + check_uid("Third", uids[2], key.uids[2]) if misc_check: - misc_check (uids[0][0], key) + misc_check(uids[0][0], key) assert len(list(c.keylist())) == 0, "Keys were imported" diff --git a/lang/python/tests/t-keylist.py b/lang/python/tests/t-keylist.py index 4505d3c9..b725fc36 100755 --- a/lang/python/tests/t-keylist.py +++ b/lang/python/tests/t-keylist.py @@ -1,282 +1,336 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + c = gpg.Context() + # Check expration of keys. This test assumes three subkeys of which # 2 are expired; it is used with the "Whisky" test key. It has # already been checked that these 3 subkeys are available. def check_whisky(name, key): - sub1 = key.subkeys[2] - sub2 = key.subkeys[3] + sub1 = key.subkeys[2] + sub2 = key.subkeys[3] + + assert sub1.expired and sub2.expired, \ + "Subkey of `{}' not flagged as expired".format(name) + assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \ + "Subkey of `{}' has wrong expiration date".format(name) - assert sub1.expired and sub2.expired, \ - "Subkey of `{}' not flagged as expired".format(name) - assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \ - "Subkey of `{}' has wrong expiration date".format(name) keys = [ - [ "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8", - [ [ "Alfa Test", "demo key", "alfa@example.net" ], - [ "Alpha Test", "demo key", "alpha@example.net" ], - [ "Alice", "demo key", "" ] ], 1 ], - [ "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F", - [ [ "Bob", "demo key", "" ], - [ "Bravo Test", "demo key", "bravo@example.net" ] ], 1 ], - [ "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60", - [ [ "Charlie Test", "demo key", "charlie@example.net" ] ], 1 ], - [ "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424", - [ [ "Delta Test", "demo key", "delta@example.net" ] ], 1 ], - [ "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D", - [ [ "Echelon", "demo key", "" ], - [ "Echo Test", "demo key", "echo@example.net" ], - [ "Eve", "demo key", "" ] ], 1 ], - [ "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E", - [ [ "Foxtrot Test", "demo key", "foxtrot@example.net" ] ], 1 ], - [ "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354", - [ [ "Golf Test", "demo key", "golf@example.net" ] ], 1 ], - [ "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A", - [ [ "Hotel Test", "demo key", "hotel@example.net" ] ], 1 ], - [ "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73", - [ [ "India Test", "demo key", "india@example.net" ] ], 1 ], - [ "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136", - [ [ "Juliet Test", "demo key", "juliet@example.net" ] ], 1 ], - [ "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02", - [ [ "Kilo Test", "demo key", "kilo@example.net" ] ], 1 ], - [ "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C", - [ [ "Lima Test", "demo key", "lima@example.net" ] ], 1 ], - [ "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8", - [ [ "Mallory", "demo key", "" ], - [ "Mike Test", "demo key", "mike@example.net" ] ], 1 ], - [ "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472", - [ [ "November Test", "demo key", "november@example.net" ] ], 1 ], - [ "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F", - [ [ "Oscar Test", "demo key", "oscar@example.net" ] ], 1 ], - [ "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C", - [ [ "Papa test", "demo key", "papa@example.net" ] ], 1 ], - [ "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4", - [ [ "Quebec Test", "demo key", "quebec@example.net" ] ], 1 ], - [ "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA", - [ [ "Romeo Test", "demo key", "romeo@example.net" ] ], 1 ], - [ "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4", - [ [ "Sierra Test", "demo key", "sierra@example.net" ] ], 1 ], - [ "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402", - [ [ "Tango Test", "demo key", "tango@example.net" ] ], 1 ], - [ "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9", - [ [ "Uniform Test", "demo key", "uniform@example.net" ] ], 1 ], - [ "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134", - [ [ "Victor Test", "demo key", "victor@example.org" ] ], 1 ], - [ "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6", - [ [ "Whisky Test", "demo key", "whisky@example.net" ] ], 3, - check_whisky ], - [ "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE", - [ [ "XRay Test", "demo key", "xray@example.net" ] ], 1 ], - [ "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD", - [ [ "Yankee Test", "demo key", "yankee@example.net" ] ], 1 ], - [ "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881", - [ [ "Zulu Test", "demo key", "zulu@example.net" ] ], 1 ], + [ + "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8", + [["Alfa Test", "demo key", + "alfa@example.net"], ["Alpha Test", "demo key", "alpha@example.net"], + ["Alice", "demo key", ""]], 1 + ], + [ + "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F", + [["Bob", "demo key", ""], + ["Bravo Test", "demo key", "bravo@example.net"]], 1 + ], + [ + "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60", + [["Charlie Test", "demo key", "charlie@example.net"]], 1 + ], + [ + "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424", + [["Delta Test", "demo key", "delta@example.net"]], 1 + ], + [ + "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D", + [["Echelon", "demo key", + ""], ["Echo Test", "demo key", "echo@example.net"], + ["Eve", "demo key", ""]], 1 + ], + [ + "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E", + [["Foxtrot Test", "demo key", "foxtrot@example.net"]], 1 + ], + [ + "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354", + [["Golf Test", "demo key", "golf@example.net"]], 1 + ], + [ + "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A", + [["Hotel Test", "demo key", "hotel@example.net"]], 1 + ], + [ + "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73", + [["India Test", "demo key", "india@example.net"]], 1 + ], + [ + "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136", + [["Juliet Test", "demo key", "juliet@example.net"]], 1 + ], + [ + "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02", + [["Kilo Test", "demo key", "kilo@example.net"]], 1 + ], + [ + "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C", + [["Lima Test", "demo key", "lima@example.net"]], 1 + ], + [ + "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8", + [["Mallory", "demo key", ""], + ["Mike Test", "demo key", "mike@example.net"]], 1 + ], + [ + "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472", + [["November Test", "demo key", "november@example.net"]], 1 + ], + [ + "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F", + [["Oscar Test", "demo key", "oscar@example.net"]], 1 + ], + [ + "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C", + [["Papa test", "demo key", "papa@example.net"]], 1 + ], + [ + "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4", + [["Quebec Test", "demo key", "quebec@example.net"]], 1 + ], + [ + "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA", + [["Romeo Test", "demo key", "romeo@example.net"]], 1 + ], + [ + "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4", + [["Sierra Test", "demo key", "sierra@example.net"]], 1 + ], + [ + "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402", + [["Tango Test", "demo key", "tango@example.net"]], 1 + ], + [ + "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9", + [["Uniform Test", "demo key", "uniform@example.net"]], 1 + ], + [ + "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134", + [["Victor Test", "demo key", "victor@example.org"]], 1 + ], + [ + "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6", + [["Whisky Test", "demo key", "whisky@example.net"]], 3, check_whisky + ], + [ + "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE", + [["XRay Test", "demo key", "xray@example.net"]], 1 + ], + [ + "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD", + [["Yankee Test", "demo key", "yankee@example.net"]], 1 + ], + [ + "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881", + [["Zulu Test", "demo key", "zulu@example.net"]], 1 + ], ] + def check_global(key, uids, n_subkeys): assert not key.revoked, "Key unexpectedly revoked" assert not key.expired, "Key unexpectedly expired" assert not key.disabled, "Key unexpectedly disabled" assert not key.invalid, "Key unexpectedly invalid" assert key.can_sign, "Key unexpectedly unusable for signing" assert key.can_certify, "Key unexpectedly unusable for certifications" assert not key.secret, "Key unexpectedly secret" - assert not key.protocol != gpg.constants.protocol.OpenPGP, \ - "Key has unexpected protocol: {}".format(key.protocol) - assert not key.issuer_serial, \ - "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial) - assert not key.issuer_name, \ - "Key unexpectedly carries issuer name: {}".format(key.issuer_name) - assert not key.chain_id, \ - "Key unexpectedly carries chain ID: {}".format(key.chain_id) + assert not key.protocol != gpg.constants.protocol.OpenPGP, + "Key has unexpected protocol: {}".format(key.protocol) + assert not key.issuer_serial, + "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial) + assert not key.issuer_name, + "Key unexpectedly carries issuer name: {}".format(key.issuer_name) + assert not key.chain_id, + "Key unexpectedly carries chain ID: {}".format(key.chain_id) # Only key Alfa is trusted - assert key.uids[0].name == 'Alfa Test' \ - or key.owner_trust == gpg.constants.validity.UNKNOWN, \ - "Key has unexpected owner trust: {}".format(key.owner_trust) - assert key.uids[0].name != 'Alfa Test' \ - or key.owner_trust == gpg.constants.validity.ULTIMATE, \ - "Key has unexpected owner trust: {}".format(key.owner_trust) + assert key.uids[0].name == 'Alfa Test' or + key.owner_trust == gpg.constants.validity.UNKNOWN, + "Key has unexpected owner trust: {}".format(key.owner_trust) + assert key.uids[0].name != 'Alfa Test' or key.owner_trust == gpg.constants. + validity.ULTIMATE, "Key has unexpected owner trust: {}". + format(key.owner_trust) - assert len(key.subkeys) - 1 == n_subkeys, \ - "Key `{}' has unexpected number of subkeys".format(uids[0][0]) + assert len(key.subkeys) - 1 == n_subkeys, + "Key `{}' has unexpected number of subkeys".format(uids[0][0]) def check_subkey(fpr, which, subkey): assert not subkey.revoked, which + " key unexpectedly revoked" assert not subkey.expired, which + " key unexpectedly expired" assert not subkey.disabled, which + " key unexpectedly disabled" assert not subkey.invalid, which + " key unexpectedly invalid" if which == "Primary": assert not subkey.can_encrypt, \ which + " key unexpectedly usable for encryption" assert subkey.can_sign, \ which + " key unexpectedly unusable for signing" assert subkey.can_certify, \ which + " key unexpectedly unusable for certifications" else: assert subkey.can_encrypt, \ which + " key unexpectedly unusable for encryption" assert not subkey.can_sign, \ which + " key unexpectedly usable for signing" assert not subkey.can_certify, \ which + " key unexpectedly usable for certifications" assert not subkey.secret, which + " key unexpectedly secret" assert not subkey.is_cardkey, "Public key marked as card key" assert not subkey.card_number, "Public key with card number set" - assert not subkey.pubkey_algo != (gpg.constants.pk.DSA if which == "Primary" - else gpg.constants.pk.ELG_E), \ - which + " key has unexpected public key algo: {}".\ - format(subkey.pubkey_algo) - assert subkey.length == 1024, \ - which + " key has unexpected length: {}".format(subkey.length) - assert fpr.endswith(subkey.keyid), \ - which + " key has unexpected key ID: {}".format(subkey.keyid) - assert which == "Secondary" or subkey.fpr == fpr, \ - which + " key has unexpected fingerprint: {}".format(subkey.fpr) - assert not subkey.expires, \ - which + " key unexpectedly expires: {}".format(subkey.expires) + assert not subkey.pubkey_algo != + (gpg.constants.pk.DSA if which == "Primary" else gpg.constants.pk.ELG_E), + which + " key has unexpected public key algo: {}".format(subkey. + pubkey_algo) + assert subkey.length == 1024, + which + " key has unexpected length: {}".format(subkey.length) + assert fpr.endswith(subkey.keyid), + which + " key has unexpected key ID: {}".format(subkey.keyid) + assert which == "Secondary" or subkey.fpr == fpr, + which + " key has unexpected fingerprint: {}".format(subkey.fpr) + assert not subkey.expires, + which + " key unexpectedly expires: {}".format(subkey.expires) + def check_uid(which, ref, uid): assert not uid.revoked, which + " user ID unexpectedly revoked" assert not uid.invalid, which + " user ID unexpectedly invalid" assert uid.validity == (gpg.constants.validity.UNKNOWN if uid.name.split()[0] not in {'Alfa', 'Alpha', 'Alice'} else - gpg.constants.validity.ULTIMATE), \ - which + " user ID has unexpectedly validity: {}".format(uid.validity) + gpg.constants.validity.ULTIMATE), + which + " user ID has unexpectedly validity: {}".format(uid.validity) assert not uid.signatures, which + " user ID unexpectedly signed" - assert uid.name == ref[0], \ - "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name) - assert uid.comment == ref[1], \ - "Unexpected comment in {} user ID: {!r}".format(which.lower(), - uid.comment) - assert uid.email == ref[2], \ - "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email) + assert uid.name == ref[0], + "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name) + assert uid.comment == ref[1], + "Unexpected comment in {} user ID: {!r}".format(which.lower(), + uid.comment) + assert uid.email == ref[2], + "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email) + i = 0 c.op_keylist_start(None, False) -key = c.op_keylist_next () +key = c.op_keylist_next() while key: try: if len(keys[i]) == 4: fpr, sec_keyid, uids, n_subkeys = keys[i] misc_check = None else: fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i] except IndexError: # There are more keys. We don't check for that. break # Global key flags. check_global(key, uids, n_subkeys) check_subkey(fpr, "Primary", key.subkeys[0]) check_subkey(sec_keyid, "Secondary", key.subkeys[1]) assert len(key.uids) == len(uids) check_uid("First", uids[0], key.uids[0]) if len(key.uids) > 1: - check_uid("Second", uids[1], key.uids[1]) + check_uid("Second", uids[1], key.uids[1]) if len(key.uids) > 2: - check_uid("Third", uids[2], key.uids[2]) + check_uid("Third", uids[2], key.uids[2]) if misc_check: - misc_check (uids[0][0], key) - key = c.op_keylist_next () + misc_check(uids[0][0], key) + key = c.op_keylist_next() i += 1 c.op_keylist_end() result = c.op_keylist_result() assert not result.truncated, "Key listing unexpectedly truncated" - # We test for a parameter-less keylist keyring_length = len(list(c.op_keylist_all())) assert keyring_length > 1,\ "Expected to find some keys, but got %r" % keyring_length # Then we do want to call with a pattern, only # i.e. without giving secret=0 alpha_keys = list(c.op_keylist_all(b"Alpha")) -assert len(alpha_keys) == 1, "Expected only one key for 'Alpha', got %r" % len(alpha_keys) - +assert len(alpha_keys) == 1, "Expected only one key for 'Alpha', got %r" % len( + alpha_keys) # Check negative result. assert len(list(c.keylist("no such key in sight"))) == 0 - for i, key in enumerate(c.keylist()): try: if len(keys[i]) == 4: fpr, sec_keyid, uids, n_subkeys = keys[i] misc_check = None else: fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i] except IndexError: # There are more keys. We don't check for that. break # Global key flags. check_global(key, uids, n_subkeys) check_subkey(fpr, "Primary", key.subkeys[0]) check_subkey(sec_keyid, "Secondary", key.subkeys[1]) assert len(key.uids) == len(uids) check_uid("First", uids[0], key.uids[0]) if len(key.uids) > 1: - check_uid("Second", uids[1], key.uids[1]) + check_uid("Second", uids[1], key.uids[1]) if len(key.uids) > 2: - check_uid("Third", uids[2], key.uids[2]) + check_uid("Third", uids[2], key.uids[2]) if misc_check: - misc_check (uids[0][0], key) - + misc_check(uids[0][0], key) # check get_key() with gpg.Context() as c: - c.get_key(support.alpha) - c.get_key(support.alpha, secret=True) - - c.get_key(support.bob) - try: - c.get_key(support.bob, secret=True) - except KeyError: - pass - else: - assert False, "Expected KeyError" - - # Legacy error - try: - c.get_key(support.no_such_key) - except gpg.errors.GPGMEError: - pass - else: - assert False, "Expected GPGMEError" + c.get_key(support.alpha) + c.get_key(support.alpha, secret=True) + + c.get_key(support.bob) + try: + c.get_key(support.bob, secret=True) + except KeyError: + pass + else: + assert False, "Expected KeyError" + + # Legacy error + try: + c.get_key(support.no_such_key) + except gpg.errors.GPGMEError: + pass + else: + assert False, "Expected GPGMEError" diff --git a/lang/python/tests/t-protocol-assuan.py b/lang/python/tests/t-protocol-assuan.py index 8da50351..c337c3b7 100755 --- a/lang/python/tests/t-protocol-assuan.py +++ b/lang/python/tests/t-protocol-assuan.py @@ -1,74 +1,77 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals with gpg.Context(protocol=gpg.constants.protocol.ASSUAN) as c: # Do nothing. err = c.assuan_transact('nop') - assert err == None + assert err is None err = c.assuan_transact(b'NOP') - assert err == None + assert err is None err = c.assuan_transact(['NOP']) - assert err == None + assert err is None err = c.assuan_transact('idontexist') assert err.getsource() == gpg.errors.SOURCE_GPGAGENT assert err.getcode() == gpg.errors.ASS_UNKNOWN_CMD # Invoke the pinentry to get a confirmation. c.assuan_transact(['GET_CONFIRMATION', 'Hello there']) data = [] + def data_cb(line): data.append(line) err = c.assuan_transact(['GETINFO', 'version'], data_cb=data_cb) assert not err assert len(data) == 1 data = [] err = c.assuan_transact(['GETINFO', 's2k_count'], data_cb=data_cb) if not err: assert len(data) == 1 assert int(data[0]) > 0 # XXX HELP sends status lines if we could use ASSUAN_CONVEY_COMMENTS. status = [] + def status_cb(line, args): status.append((line, args)) alphas_grip = '76F7E2B35832976B50A27A282D9B87E44577EB66' err = c.assuan_transact(['KEYINFO', alphas_grip], status_cb=status_cb) if not err: assert len(status) == 1 line, args = status[0] assert line.startswith('KEYINFO') assert args.startswith(alphas_grip) # XXX: test these callbacks, e.g. using PRESET_PASSPHRASE # XXX: once issue2428 is resolved def inq_cb(name, args): print("inq_cb", name, args) diff --git a/lang/python/tests/t-quick-key-creation.py b/lang/python/tests/t-quick-key-creation.py index 8b7372e7..47209288 100755 --- a/lang/python/tests/t-quick-key-creation.py +++ b/lang/python/tests/t-quick-key-creation.py @@ -1,140 +1,148 @@ #!/usr/bin/env python # Copyright (C) 2017 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import itertools import time import support support.assert_gpg_version((2, 1, 2)) +del absolute_import, print_function, unicode_literals + alpha = "Alpha " with support.EphemeralContext() as ctx: res = ctx.create_key(alpha) keys = list(ctx.keylist()) assert len(keys) == 1, "Weird number of keys created" key = keys[0] assert key.fpr == res.fpr assert len(key.subkeys) == 2, "Expected one primary key and one subkey" assert key.subkeys[0].expires > 0, "Expected primary key to expire" # Try to create a key with the same UID try: ctx.create_key(alpha) assert False, "Expected an error but got none" except gpg.errors.GpgError as e: pass # Try to create a key with the same UID, now with force! res2 = ctx.create_key(alpha, force=True) assert res.fpr != res2.fpr - # From here on, we use one context, and create unique UIDs uid_counter = 0 + + def make_uid(): global uid_counter uid_counter += 1 return "user{0}@invalid.example.org".format(uid_counter) + with support.EphemeralContext() as ctx: # Check gpg.constants.create.NOEXPIRE... res = ctx.create_key(make_uid(), expires=False) key = ctx.get_key(res.fpr, secret=True) assert key.fpr == res.fpr assert len(key.subkeys) == 2, "Expected one primary key and one subkey" assert key.subkeys[0].expires == 0, "Expected primary key not to expire" t = 2 * 24 * 60 * 60 slack = 5 * 60 res = ctx.create_key(make_uid(), expires_in=t) key = ctx.get_key(res.fpr, secret=True) assert key.fpr == res.fpr assert len(key.subkeys) == 2, "Expected one primary key and one subkey" assert abs(time.time() + t - key.subkeys[0].expires) < slack, \ "Primary keys expiration time is off" # Check capabilities - for sign, encrypt, certify, authenticate in itertools.product([False, True], - [False, True], - [False, True], - [False, True]): + for sign, encrypt, certify, authenticate in itertools. + product([False, True], [False, True], [False, True], [False, True]): # Filter some out if not (sign or encrypt or certify or authenticate): # This triggers the default capabilities tested before. continue if (sign or encrypt or authenticate) and not certify: # The primary key always certifies. continue - res = ctx.create_key(make_uid(), algorithm="rsa", - sign=sign, encrypt=encrypt, certify=certify, - authenticate=authenticate) + res = ctx.create_key( + make_uid(), + algorithm="rsa", + sign=sign, + encrypt=encrypt, + certify=certify, + authenticate=authenticate) key = ctx.get_key(res.fpr, secret=True) assert key.fpr == res.fpr assert len(key.subkeys) == 1, \ "Expected no subkey for non-default capabilities" p = key.subkeys[0] assert sign == p.can_sign assert encrypt == p.can_encrypt assert certify == p.can_certify assert authenticate == p.can_authenticate # Check algorithm res = ctx.create_key(make_uid(), algorithm="rsa") key = ctx.get_key(res.fpr, secret=True) assert key.fpr == res.fpr for k in key.subkeys: assert k.pubkey_algo == 1 # Check algorithm with size res = ctx.create_key(make_uid(), algorithm="rsa1024") key = ctx.get_key(res.fpr, secret=True) assert key.fpr == res.fpr for k in key.subkeys: assert k.pubkey_algo == 1 assert k.length == 1024 # Check algorithm future-default ctx.create_key(make_uid(), algorithm="future-default") # Check passphrase protection recipient = make_uid() passphrase = "streng geheim" res = ctx.create_key(recipient, passphrase=passphrase) - ciphertext, _, _ = ctx.encrypt(b"hello there", recipients=[ctx.get_key(res.fpr)]) + ciphertext, _, _ = ctx.encrypt( + b"hello there", recipients=[ctx.get_key(res.fpr)]) cb_called = False + def cb(*args): global cb_called cb_called = True return passphrase + ctx.pinentry_mode = gpg.constants.PINENTRY_MODE_LOOPBACK ctx.set_passphrase_cb(cb) plaintext, _, _ = ctx.decrypt(ciphertext) assert plaintext == b"hello there" assert cb_called diff --git a/lang/python/tests/t-quick-key-manipulation.py b/lang/python/tests/t-quick-key-manipulation.py index 37e05b35..ade171e7 100755 --- a/lang/python/tests/t-quick-key-manipulation.py +++ b/lang/python/tests/t-quick-key-manipulation.py @@ -1,130 +1,133 @@ #!/usr/bin/env python # Copyright (C) 2017 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import sys import support support.assert_gpg_version((2, 1, 14)) +del absolute_import, print_function, unicode_literals + alpha = "Alpha " bravo = "Bravo " with support.EphemeralContext() as ctx: res = ctx.create_key(alpha, certify=True) key = ctx.get_key(res.fpr) assert len(key.subkeys) == 1, "Expected one primary key and no subkeys" assert len(key.uids) == 1, "Expected exactly one UID" def get_uid(uid): key = ctx.get_key(res.fpr) for u in key.uids: if u.uid == uid: return u return None # sanity check uid = get_uid(alpha) assert uid, "UID alpha not found" assert uid.revoked == 0 # add bravo ctx.key_add_uid(key, bravo) uid = get_uid(bravo) assert uid, "UID bravo not found" assert uid.revoked == 0 # revoke alpha ctx.key_revoke_uid(key, alpha) uid = get_uid(alpha) assert uid, "UID alpha not found" assert uid.revoked == 1 uid = get_uid(bravo) assert uid, "UID bravo not found" assert uid.revoked == 0 # try to revoke the last UID try: ctx.key_revoke_uid(key, alpha) # IMHO this should fail. issue2961. # assert False, "Expected an error but got none" except gpg.errors.GpgError: pass # Everything should be the same uid = get_uid(alpha) assert uid, "UID alpha not found" assert uid.revoked == 1 uid = get_uid(bravo) assert uid, "UID bravo not found" assert uid.revoked == 0 # try to revoke a non-existent UID try: ctx.key_revoke_uid(key, "i dont exist") # IMHO this should fail. issue2963. # assert False, "Expected an error but got none" except gpg.errors.GpgError: pass # try to add an pre-existent UID try: ctx.key_add_uid(key, bravo) assert False, "Expected an error but got none" except gpg.errors.GpgError: pass # Check setting the TOFU policy. with open(os.path.join(ctx.home_dir, "gpg.conf"), "a") as handle: handle.write("trust-model tofu+pgp\n") if not support.have_tofu_support(ctx, bravo): print("GnuPG does not support TOFU, skipping TOFU tests.") sys.exit() for name, policy in [(name, getattr(gpg.constants.tofu.policy, name)) for name in filter(lambda x: not x.startswith('__'), dir(gpg.constants.tofu.policy))]: if policy == gpg.constants.tofu.policy.NONE: # We must not set the policy to NONE. continue ctx.key_tofu_policy(key, policy) - keys = list(ctx.keylist(key.uids[0].uid, - mode=(gpg.constants.keylist.mode.LOCAL - |gpg.constants.keylist.mode.WITH_TOFU))) + keys = list( + ctx.keylist( + key.uids[0].uid, + mode=(gpg.constants.keylist.mode.LOCAL | + gpg.constants.keylist.mode.WITH_TOFU))) assert len(keys) == 1 if policy == gpg.constants.tofu.policy.AUTO: # We cannot check that it is set to AUTO. continue for uid in keys[0].uids: if uid.uid == alpha: # TOFU information of revoked UIDs is not updated. # XXX: Is that expected? continue assert uid.tofu[0].policy == policy, \ "Expected policy {0} ({1}), got {2}".format(policy, name, uid.tofu[0].policy) diff --git a/lang/python/tests/t-quick-key-signing.py b/lang/python/tests/t-quick-key-signing.py index 3d648c5b..6f9b8a72 100755 --- a/lang/python/tests/t-quick-key-signing.py +++ b/lang/python/tests/t-quick-key-signing.py @@ -1,121 +1,133 @@ #!/usr/bin/env python # Copyright (C) 2017 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import itertools import time import support support.assert_gpg_version((2, 1, 1)) +del absolute_import, print_function, unicode_literals + with support.EphemeralContext() as ctx: uid_counter = 0 + def make_uid(): global uid_counter uid_counter += 1 return "user{0}@invalid.example.org".format(uid_counter) def make_key(): uids = [make_uid() for i in range(3)] res = ctx.create_key(uids[0], certify=True) key = ctx.get_key(res.fpr) for u in uids[1:]: ctx.key_add_uid(key, u) return key, uids def check_sigs(key, expected_sigs): - keys = list(ctx.keylist(key.fpr, mode=(gpg.constants.keylist.mode.LOCAL - |gpg.constants.keylist.mode.SIGS))) + keys = list( + ctx.keylist( + key.fpr, + mode=(gpg.constants.keylist.mode.LOCAL | + gpg.constants.keylist.mode.SIGS))) assert len(keys) == 1 - key_uids = {uid.uid: [s for s in uid.signatures] for uid in keys[0].uids} + key_uids = { + uid.uid: [s for s in uid.signatures] + for uid in keys[0].uids + } expected = list(expected_sigs) while key_uids and expected: uid, signing_key, func = expected[0] match = False for i, s in enumerate(key_uids[uid]): if signing_key.fpr.endswith(s.keyid): if func: func(s) match = True break if match: expected.pop(0) key_uids[uid].pop(i) if not key_uids[uid]: del key_uids[uid] assert not key_uids, "Superfluous signatures: {0}".format(key_uids) assert not expected, "Missing signatures: {0}".format(expected) # Simplest case. Sign without any options. key_a, uids_a = make_key() key_b, uids_b = make_key() ctx.signers = [key_a] def exportable_non_expiring(s): assert s.exportable assert s.expires == 0 - check_sigs(key_b, itertools.product(uids_b, [key_b], [exportable_non_expiring])) + check_sigs(key_b, + itertools.product(uids_b, [key_b], [exportable_non_expiring])) ctx.key_sign(key_b) - check_sigs(key_b, itertools.product(uids_b, [key_b, key_a], [exportable_non_expiring])) + check_sigs( + key_b, + itertools.product(uids_b, [key_b, key_a], [exportable_non_expiring])) # Create a non-exportable signature, and explicitly name all uids. key_c, uids_c = make_key() ctx.signers = [key_a, key_b] def non_exportable_non_expiring(s): assert s.exportable == 0 assert s.expires == 0 ctx.key_sign(key_c, local=True, uids=uids_c) - check_sigs(key_c, - list(itertools.product(uids_c, [key_c], - [exportable_non_expiring])) - + list(itertools.product(uids_c, [key_b, key_a], - [non_exportable_non_expiring]))) + check_sigs( + key_c, + list(itertools.product(uids_c, [key_c], [exportable_non_expiring])) + + list( + itertools.product(uids_c, [key_b, key_a], + [non_exportable_non_expiring]))) # Create a non-exportable, expiring signature for a single uid. key_d, uids_d = make_key() ctx.signers = [key_c] expires_in = 600 slack = 10 def non_exportable_expiring(s): assert s.exportable == 0 assert abs(time.time() + expires_in - s.expires) < slack ctx.key_sign(key_d, local=True, expires_in=expires_in, uids=uids_d[0]) - check_sigs(key_d, - list(itertools.product(uids_d, [key_d], - [exportable_non_expiring])) - + list(itertools.product(uids_d[:1], [key_c], - [non_exportable_expiring]))) + check_sigs( + key_d, + list(itertools.product(uids_d, [key_d], [exportable_non_expiring])) + + list( + itertools.product(uids_d[:1], [key_c], [non_exportable_expiring]))) # Now sign the second in the same fashion, but use a singleton list. ctx.key_sign(key_d, local=True, expires_in=expires_in, uids=uids_d[1:2]) - check_sigs(key_d, - list(itertools.product(uids_d, [key_d], - [exportable_non_expiring])) - + list(itertools.product(uids_d[:2], [key_c], - [non_exportable_expiring]))) + check_sigs( + key_d, + list(itertools.product(uids_d, [key_d], [exportable_non_expiring])) + + list( + itertools.product(uids_d[:2], [key_c], [non_exportable_expiring]))) diff --git a/lang/python/tests/t-quick-subkey-creation.py b/lang/python/tests/t-quick-subkey-creation.py index ad4f35c6..30424c19 100755 --- a/lang/python/tests/t-quick-subkey-creation.py +++ b/lang/python/tests/t-quick-subkey-creation.py @@ -1,112 +1,115 @@ #!/usr/bin/env python # Copyright (C) 2017 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import itertools import time import support +del absolute_import, print_function, unicode_literals + alpha = "Alpha " bravo = "Bravo " with support.EphemeralContext() as ctx: res = ctx.create_key(alpha, certify=True) keys = list(ctx.keylist()) assert len(keys) == 1, "Weird number of keys created" key = keys[0] assert key.fpr == res.fpr assert len(key.subkeys) == 1, "Expected one primary key and no subkeys" def get_subkey(fpr): k = ctx.get_key(fpr) for sk in k.subkeys: if sk.fpr == fpr: return sk return None # Check gpg.constants.create.NOEXPIRE... res = ctx.create_subkey(key, expires=False) subkey = get_subkey(res.fpr) assert subkey.expires == 0, "Expected subkey not to expire" assert subkey.can_encrypt, \ "Default subkey capabilities do not include encryption" t = 2 * 24 * 60 * 60 slack = 5 * 60 res = ctx.create_subkey(key, expires_in=t) subkey = get_subkey(res.fpr) assert abs(time.time() + t - subkey.expires) < slack, \ "subkeys expiration time is off" # Check capabilities - for sign, encrypt, authenticate in itertools.product([False, True], - [False, True], - [False, True]): + for sign, encrypt, authenticate in itertools. + product([False, True], [False, True], [False, True]): # Filter some out if not (sign or encrypt or authenticate): # This triggers the default capabilities tested before. continue - res = ctx.create_subkey(key, sign=sign, encrypt=encrypt, - authenticate=authenticate) + res = ctx.create_subkey( + key, sign=sign, encrypt=encrypt, authenticate=authenticate) subkey = get_subkey(res.fpr) assert sign == subkey.can_sign assert encrypt == subkey.can_encrypt assert authenticate == subkey.can_authenticate # Check algorithm res = ctx.create_subkey(key, algorithm="rsa") subkey = get_subkey(res.fpr) assert subkey.pubkey_algo == 1 # Check algorithm with size res = ctx.create_subkey(key, algorithm="rsa1024") subkey = get_subkey(res.fpr) assert subkey.pubkey_algo == 1 assert subkey.length == 1024 # Check algorithm future-default ctx.create_subkey(key, algorithm="future-default") # Check passphrase protection. For this we create a new key # so that we have a key with just one encryption subkey. bravo_res = ctx.create_key(bravo, certify=True) bravo_key = ctx.get_key(bravo_res.fpr) - assert len(bravo_key.subkeys) == 1, "Expected one primary key and no subkeys" + assert len( + bravo_key.subkeys) == 1, "Expected one primary key and no subkeys" passphrase = "streng geheim" res = ctx.create_subkey(bravo_key, passphrase=passphrase) - ciphertext, _, _ = ctx.encrypt(b"hello there", - recipients=[ctx.get_key(bravo_res.fpr)]) + ciphertext, _, _ = ctx.encrypt( + b"hello there", recipients=[ctx.get_key(bravo_res.fpr)]) cb_called = False + def cb(*args): global cb_called cb_called = True return passphrase + ctx.pinentry_mode = gpg.constants.PINENTRY_MODE_LOOPBACK ctx.set_passphrase_cb(cb) plaintext, _, _ = ctx.decrypt(ciphertext) assert plaintext == b"hello there" assert cb_called diff --git a/lang/python/tests/t-sig-notation.py b/lang/python/tests/t-sig-notation.py index bc8da2e6..5960f443 100755 --- a/lang/python/tests/t-sig-notation.py +++ b/lang/python/tests/t-sig-notation.py @@ -1,79 +1,81 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals expected_notations = { - "laughing@me": ("Just Squeeze Me", gpg.constants.sig.notation.HUMAN_READABLE), - "preferred-email-encoding@pgp.com": ("pgpmime", - gpg.constants.sig.notation.HUMAN_READABLE - | gpg.constants.sig.notation.CRITICAL), + "laughing@me": ("Just Squeeze Me", + gpg.constants.sig.notation.HUMAN_READABLE), + "preferred-email-encoding@pgp.com": + ("pgpmime", gpg.constants.sig.notation.HUMAN_READABLE | + gpg.constants.sig.notation.CRITICAL), None: ("http://www.gnu.org/policy/", 0), } # GnuPG prior to 2.1.13 did not report the critical flag correctly. with gpg.Context() as c: version = c.engine_info.version - have_correct_sig_data = not (version.startswith("1.") - or version.startswith("2.0.") - or version == "2.1.1" - or (version.startswith("2.1.1") - and version[5] < '3')) + have_correct_sig_data = not ( + version.startswith("1.") or version.startswith("2.0.") or + (version.startswith("2.1.") and int(version[4:]) < 13)) + def check_result(result): assert len(result.signatures) == 1, "Unexpected number of signatures" sig = result.signatures[0] assert len(sig.notations) == len(expected_notations) for r in sig.notations: - assert not 'name_len' in dir(r) - assert not 'value_len' in dir(r) + assert 'name_len' not in dir(r) + assert 'value_len' not in dir(r) assert r.name in expected_notations value, flags = expected_notations.pop(r.name) assert r.value == value, \ "Expected {!r}, got {!r}".format(value, r.value) assert r.human_readable \ == bool(flags & gpg.constants.sig.notation.HUMAN_READABLE) assert r.critical \ == (bool(flags & gpg.constants.sig.notation.CRITICAL) if have_correct_sig_data else False) assert len(expected_notations) == 0 + source = gpg.Data("Hallo Leute\n") signed = gpg.Data() c = gpg.Context() for name, (value, flags) in expected_notations.items(): c.sig_notation_add(name, value, flags) c.op_sign(source, signed, gpg.constants.sig.mode.NORMAL) signed.seek(0, os.SEEK_SET) sink = gpg.Data() c.op_verify(signed, None, sink) result = c.op_verify_result() check_result(result) diff --git a/lang/python/tests/t-sign.py b/lang/python/tests/t-sign.py index d3757294..3ad05e8e 100755 --- a/lang/python/tests/t-sign.py +++ b/lang/python/tests/t-sign.py @@ -1,119 +1,121 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import os import gpg import support +del absolute_import, print_function, unicode_literals + + def fail(msg): raise RuntimeError(msg) + def check_result(r, typ): if r.invalid_signers: fail("Invalid signer found: {}".format(r.invalid_signers.fpr)) if len(r.signatures) != 1: fail("Unexpected number of signatures created") signature = r.signatures[0] if signature.type != typ: fail("Wrong type of signature created") if signature.pubkey_algo != gpg.constants.pk.DSA: fail("Wrong pubkey algorithm reported: {}".format( signature.pubkey_algo)) if signature.hash_algo != gpg.constants.md.SHA1: - fail("Wrong hash algorithm reported: {}".format( - signature.hash_algo)) + fail("Wrong hash algorithm reported: {}".format(signature.hash_algo)) if signature.sig_class != 1: - fail("Wrong signature class reported: {}".format( - signature.sig_class)) + fail("Wrong signature class reported: {}".format(signature.sig_class)) if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734": fail("Wrong fingerprint reported: {}".format(signature.fpr)) + c = gpg.Context() c.set_textmode(True) c.set_armor(True) source = gpg.Data("Hallo Leute\n") sink = gpg.Data() c.op_sign(source, sink, gpg.constants.sig.mode.NORMAL) result = c.op_sign_result() check_result(result, gpg.constants.sig.mode.NORMAL) support.print_data(sink) # Now a detached signature. source.seek(0, os.SEEK_SET) sink = gpg.Data() c.op_sign(source, sink, gpg.constants.sig.mode.DETACH) result = c.op_sign_result() check_result(result, gpg.constants.sig.mode.DETACH) support.print_data(sink) # And finally a cleartext signature. */ source.seek(0, os.SEEK_SET) sink = gpg.Data() c.op_sign(source, sink, gpg.constants.sig.mode.CLEAR) result = c.op_sign_result() check_result(result, gpg.constants.sig.mode.CLEAR) support.print_data(sink) # Idiomatic interface. with gpg.Context(armor=True, textmode=True) as c: message = "Hallo Leute\n".encode() signed, _ = c.sign(message) assert len(signed) > 0 assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found' signed, _ = c.sign(message, mode=gpg.constants.sig.mode.DETACH) assert len(signed) > 0 assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' signed, _ = c.sign(message, mode=gpg.constants.sig.mode.CLEAR) assert len(signed) > 0 assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found' assert signed.find(message) > 0, 'Message content not found' assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' with gpg.Context() as c: message = "Hallo Leute\n".encode() c.signers = [c.get_key(support.sign_only, True)] c.sign(message) c.signers = [c.get_key(support.encrypt_only, True)] try: c.sign(message) except gpg.errors.InvalidSigners as e: assert len(e.signers) == 1 assert support.encrypt_only.endswith(e.signers[0].fpr) else: assert False, "Expected an InvalidSigners error, got none" diff --git a/lang/python/tests/t-signers.py b/lang/python/tests/t-signers.py index 5864ee5f..119ab773 100755 --- a/lang/python/tests/t-signers.py +++ b/lang/python/tests/t-signers.py @@ -1,95 +1,99 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support +del absolute_import, print_function, unicode_literals + + def fail(msg): raise RuntimeError(msg) + def check_result(r, typ): if r.invalid_signers: fail("Invalid signer found: {}".format(r.invalid_signers.fpr)) if len(r.signatures) != 2: fail("Unexpected number of signatures created") for signature in r.signatures: if signature.type != typ: fail("Wrong type of signature created") if signature.pubkey_algo != gpg.constants.pk.DSA: fail("Wrong pubkey algorithm reported: {}".format( signature.pubkey_algo)) if signature.hash_algo != gpg.constants.md.SHA1: fail("Wrong hash algorithm reported: {}".format( signature.hash_algo)) if signature.sig_class != 1: fail("Wrong signature class reported: got {}, want {}".format( signature.sig_class, 1)) if signature.fpr not in ("A0FF4590BB6122EDEF6E3C542D727CC768697734", "23FD347A419429BACCD5E72D6BC4778054ACD246"): fail("Wrong fingerprint reported: {}".format(signature.fpr)) + c = gpg.Context() c.set_textmode(True) c.set_armor(True) keys = [] c.op_keylist_start('', True) keys.append(c.op_keylist_next()) keys.append(c.op_keylist_next()) c.op_keylist_end() c.signers_add(keys[0]) c.signers_add(keys[1]) for mode in (gpg.constants.sig.mode.NORMAL, gpg.constants.sig.mode.DETACH, gpg.constants.sig.mode.CLEAR): source = gpg.Data("Hallo Leute\n") sink = gpg.Data() c.op_sign(source, sink, mode) result = c.op_sign_result() check_result(result, mode) support.print_data(sink) # Idiomatic interface. with gpg.Context(armor=True, textmode=True, signers=keys) as c: message = "Hallo Leute\n".encode() signed, result = c.sign(message) check_result(result, gpg.constants.sig.mode.NORMAL) assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found' signed, result = c.sign(message, mode=gpg.constants.sig.mode.DETACH) check_result(result, gpg.constants.sig.mode.DETACH) assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' signed, result = c.sign(message, mode=gpg.constants.sig.mode.CLEAR) check_result(result, gpg.constants.sig.mode.CLEAR) assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found' assert signed.find(message) > 0, 'Message content not found' assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found' diff --git a/lang/python/tests/t-trustlist.py b/lang/python/tests/t-trustlist.py index 89524bb5..ffa0b96d 100755 --- a/lang/python/tests/t-trustlist.py +++ b/lang/python/tests/t-trustlist.py @@ -1,43 +1,46 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals c = gpg.Context() + def dump_item(item): - print("l={} k={} t={} o={} v={} u={}".format( - item.level, item.keyid, item.type, item.owner_trust, - item.validity, item.name)) + print("l={} k={} t={} o={} v={} u={}".format(item.level, item.keyid, + item.type, item.owner_trust, + item.validity, item.name)) + c.op_trustlist_start("alice", 0) while True: item = c.op_trustlist_next() if not item: break dump_item(item) c.op_trustlist_end() for item in c.op_trustlist_all("alice", 0): dump_item(item) diff --git a/lang/python/tests/t-verify.py b/lang/python/tests/t-verify.py index 320dae66..70a6c1cb 100755 --- a/lang/python/tests/t-verify.py +++ b/lang/python/tests/t-verify.py @@ -1,193 +1,197 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import sys import os import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals test_text1 = b"Just GNU it!\n" -test_text1f= b"Just GNU it?\n" +test_text1f = b"Just GNU it?\n" test_sig1 = b"""-----BEGIN PGP SIGNATURE----- iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA== =nts1 -----END PGP SIGNATURE----- """ test_sig2 = b"""-----BEGIN PGP MESSAGE----- owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf y1kvP4y+8D5a11ang0udywsA =Crq6 -----END PGP MESSAGE----- """ # A message with a prepended but unsigned plaintext packet. double_plaintext_sig = b"""-----BEGIN PGP MESSAGE----- rDRiCmZvb2Jhci50eHRF4pxNVGhpcyBpcyBteSBzbmVha3kgcGxhaW50ZXh0IG1l c3NhZ2UKowGbwMvMwCSoW1RzPCOz3IRxTWISa6JebnG666MFD1wzSzJSixQ81XMV UlITUxTyixRyKxXKE0uSMxQyEosVikvyCwpSU/S4FNCArq6Ce1F+aXJGvoJvYlGF erFCTmJxiUJ5flFKMVeHGwuDIBMDGysTyA4GLk4BmO036xgWzMgzt9V85jCtfDFn UqVooWlGXHwNw/xg/fVzt9VNbtjtJ/fhUqYo0/LyCGEA =6+AK -----END PGP MESSAGE----- """ + def check_result(result, summary, validity, fpr, status, notation): assert len(result.signatures) == 1, "Unexpected number of signatures" sig = result.signatures[0] assert sig.summary == summary, \ "Unexpected signature summary: {}, want: {}".format(sig.summary, summary) assert sig.fpr == fpr assert gpg.errors.GPGMEError(sig.status).getcode() == status if notation: expected_notations = { "bar": (b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f" + b" das waren Umlaute und jetzt ein prozent%-Zeichen" if sys.version_info[0] < 3 else b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f".decode() + " das waren Umlaute und jetzt ein prozent%-Zeichen"), - "foobar.1": "this is a notation data with 2 lines", - None: "http://www.gu.org/policy/", + "foobar.1": + "this is a notation data with 2 lines", + None: + "http://www.gu.org/policy/", } assert len(sig.notations) == len(expected_notations) for r in sig.notations: - assert not 'name_len' in dir(r) - assert not 'value_len' in dir(r) + assert 'name_len' not in dir(r) + assert 'value_len' not in dir(r) assert r.name in expected_notations assert r.value == expected_notations[r.name], \ "Expected {!r}, got {!r}".format(expected_notations[r.name], r.value) expected_notations.pop(r.name) assert len(expected_notations) == 0 assert not sig.wrong_key_usage assert sig.validity == validity, \ "Unexpected signature validity: {}, want: {}".format( sig.validity, validity) - assert gpg.errors.GPGMEError(sig.validity_reason).getcode() == gpg.errors.NO_ERROR + assert gpg.errors.GPGMEError( + sig.validity_reason).getcode() == gpg.errors.NO_ERROR + c = gpg.Context() c.set_armor(True) # Checking a valid message. text = gpg.Data(test_text1) sig = gpg.Data(test_sig1) c.op_verify(sig, text, None) result = c.op_verify_result() check_result(result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, gpg.constants.validity.FULL, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR, True) - + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR, + True) # Checking a manipulated message. text = gpg.Data(test_text1f) sig.seek(0, os.SEEK_SET) c.op_verify(sig, text, None) result = c.op_verify_result() check_result(result, gpg.constants.sigsum.RED, gpg.constants.validity.UNKNOWN, "2D727CC768697734", gpg.errors.BAD_SIGNATURE, False) # Checking a normal signature. text = gpg.Data() sig = gpg.Data(test_sig2) c.op_verify(sig, None, text) result = c.op_verify_result() check_result(result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, gpg.constants.validity.FULL, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR, False) + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR, + False) # Checking an invalid message. text = gpg.Data() sig = gpg.Data(double_plaintext_sig) try: c.op_verify(sig, None, text) except Exception as e: assert type(e) == gpg.errors.GPGMEError assert e.getcode() == gpg.errors.BAD_DATA else: assert False, "Expected an error but got none." - # Idiomatic interface. with gpg.Context(armor=True) as c: # Checking a valid message. _, result = c.verify(test_text1, test_sig1) - check_result(result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, - gpg.constants.validity.FULL, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR, True) + check_result( + result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, + gpg.constants.validity.FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR, True) # Checking a manipulated message. try: c.verify(test_text1f, test_sig1) except gpg.errors.BadSignatures as e: check_result(e.result, gpg.constants.sigsum.RED, - gpg.constants.validity.UNKNOWN, - "2D727CC768697734", gpg.errors.BAD_SIGNATURE, False) + gpg.constants.validity.UNKNOWN, "2D727CC768697734", + gpg.errors.BAD_SIGNATURE, False) else: assert False, "Expected an error but got none." # Checking a normal signature. sig = gpg.Data(test_sig2) data, result = c.verify(test_sig2) - check_result(result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, - gpg.constants.validity.FULL, - "A0FF4590BB6122EDEF6E3C542D727CC768697734", - gpg.errors.NO_ERROR, False) + check_result( + result, gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN, + gpg.constants.validity.FULL, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", gpg.errors.NO_ERROR, False) assert data == test_text1 # Checking an invalid message. try: c.verify(double_plaintext_sig) except gpg.errors.GPGMEError as e: assert e.getcode() == gpg.errors.BAD_DATA else: assert False, "Expected an error but got none." alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) # Checking a valid message. c.verify(test_text1, test_sig1, verify=[alpha]) try: c.verify(test_text1, test_sig1, verify=[alpha, bob]) except gpg.errors.MissingSignatures as e: assert len(e.missing) == 1 assert e.missing[0] == bob else: assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-wait.py b/lang/python/tests/t-wait.py index 31013011..907f4504 100755 --- a/lang/python/tests/t-wait.py +++ b/lang/python/tests/t-wait.py @@ -1,45 +1,46 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals import time import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. + +del absolute_import, print_function, unicode_literals c = gpg.Context() c.set_armor(True) # Checking a message without a signature. sig = gpg.Data("foo\n") text = gpg.Data() c.op_verify_start(sig, None, text) try: while True: err = c.wait(False) if err: break time.sleep(0.1) except Exception as e: assert e.getcode() == gpg.errors.NO_DATA else: assert False, "Expected an error, got none" diff --git a/lang/python/tests/t-wrapper.py b/lang/python/tests/t-wrapper.py index 08a320d2..020e71e5 100755 --- a/lang/python/tests/t-wrapper.py +++ b/lang/python/tests/t-wrapper.py @@ -1,27 +1,27 @@ #!/usr/bin/env python # Copyright (C) 2016 g10 Code GmbH # # This file is part of GPGME. # # GPGME is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPGME is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . import gpg import support -_ = support # to appease pyflakes. +_ = support # to appease pyflakes. d0 = gpg.Data() -d0.seek # trigger on-demand-wrapping +d0.seek # trigger on-demand-wrapping assert d0.seek == d0.seek, "Generated wrapper functions are not cached" assert hasattr(gpg.Data, 'seek'), "Generated wrapper functions are not shared"