From 2fac017618a76882605125b05ff1f7393fe99860 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 28 Oct 2016 16:45:49 -0400 Subject: python: Rename Python module from PyME to gpg. This follows weeks of discussion on the gnupg-devel mailing list. Hopefully it will make it easier for people using Python to use GnuPG in the future. Signed-off-by: Daniel Kahn Gillmor --- NEWS | 1 + configure.ac | 2 +- lang/README | 2 +- lang/python/MANIFEST.in | 2 +- lang/python/Makefile.am | 44 +- lang/python/README | 12 +- lang/python/docs/Short_History.rst | 8 +- lang/python/examples/assuan.py | 4 +- lang/python/examples/decryption-filter.py | 6 +- lang/python/examples/delkey.py | 6 +- lang/python/examples/encrypt-to-all.py | 6 +- lang/python/examples/exportimport.py | 12 +- lang/python/examples/genkey.py | 8 +- lang/python/examples/inter-edit.py | 4 +- lang/python/examples/sign.py | 6 +- lang/python/examples/signverify.py | 10 +- lang/python/examples/simple.py | 4 +- lang/python/examples/testCMSgetkey.py | 4 +- lang/python/examples/verifydetails.py | 4 +- lang/python/gpg/__init__.py | 121 +++ lang/python/gpg/callbacks.py | 49 + lang/python/gpg/constants/__init__.py | 114 +++ lang/python/gpg/constants/data/__init__.py | 6 + lang/python/gpg/constants/data/encoding.py | 22 + lang/python/gpg/constants/event.py | 22 + lang/python/gpg/constants/import.py | 22 + lang/python/gpg/constants/keylist/__init__.py | 6 + lang/python/gpg/constants/keylist/mode.py | 22 + lang/python/gpg/constants/md.py | 22 + lang/python/gpg/constants/pk.py | 22 + lang/python/gpg/constants/protocol.py | 22 + lang/python/gpg/constants/sig/__init__.py | 6 + lang/python/gpg/constants/sig/mode.py | 22 + lang/python/gpg/constants/sigsum.py | 22 + lang/python/gpg/constants/status.py | 124 +++ lang/python/gpg/constants/validity.py | 22 + lang/python/gpg/core.py | 1164 ++++++++++++++++++++++++ lang/python/gpg/errors.py | 127 +++ lang/python/gpg/results.py | 118 +++ lang/python/gpg/util.py | 53 ++ lang/python/gpg/version.py.in | 68 ++ lang/python/gpgme.i | 32 +- lang/python/helpers.c | 124 +-- lang/python/helpers.h | 12 +- lang/python/private.h | 28 +- lang/python/pyme/__init__.py | 125 --- lang/python/pyme/callbacks.py | 49 - lang/python/pyme/constants/__init__.py | 114 --- lang/python/pyme/constants/data/__init__.py | 6 - lang/python/pyme/constants/data/encoding.py | 22 - lang/python/pyme/constants/event.py | 22 - lang/python/pyme/constants/import.py | 22 - lang/python/pyme/constants/keylist/__init__.py | 6 - lang/python/pyme/constants/keylist/mode.py | 22 - lang/python/pyme/constants/md.py | 22 - lang/python/pyme/constants/pk.py | 22 - lang/python/pyme/constants/protocol.py | 22 - lang/python/pyme/constants/sig/__init__.py | 6 - lang/python/pyme/constants/sig/mode.py | 22 - lang/python/pyme/constants/sigsum.py | 22 - lang/python/pyme/constants/status.py | 124 --- lang/python/pyme/constants/validity.py | 22 - lang/python/pyme/core.py | 1164 ------------------------ lang/python/pyme/errors.py | 127 --- lang/python/pyme/results.py | 118 --- lang/python/pyme/util.py | 53 -- lang/python/pyme/version.py.in | 68 -- lang/python/setup.py.in | 14 +- lang/python/tests/initial.py | 6 +- lang/python/tests/support.py | 2 +- lang/python/tests/t-callbacks.py | 4 +- lang/python/tests/t-data.py | 2 +- lang/python/tests/t-decrypt-verify.py | 6 +- lang/python/tests/t-decrypt.py | 6 +- lang/python/tests/t-edit.py | 2 +- lang/python/tests/t-encrypt-large.py | 2 +- lang/python/tests/t-encrypt-sign.py | 8 +- lang/python/tests/t-encrypt-sym.py | 6 +- lang/python/tests/t-encrypt.py | 8 +- lang/python/tests/t-export.py | 2 +- lang/python/tests/t-file-name.py | 2 +- lang/python/tests/t-idiomatic.py | 18 +- lang/python/tests/t-import.py | 2 +- lang/python/tests/t-keylist.py | 8 +- lang/python/tests/t-protocol-assuan.py | 8 +- lang/python/tests/t-sig-notation.py | 2 +- lang/python/tests/t-sign.py | 14 +- lang/python/tests/t-signers.py | 6 +- lang/python/tests/t-trustlist.py | 2 +- lang/python/tests/t-verify.py | 6 +- lang/python/tests/t-wait.py | 2 +- lang/python/tests/t-wrapper.py | 2 +- 92 files changed, 2419 insertions(+), 2418 deletions(-) create mode 100644 lang/python/gpg/__init__.py create mode 100644 lang/python/gpg/callbacks.py create mode 100644 lang/python/gpg/constants/__init__.py create mode 100644 lang/python/gpg/constants/data/__init__.py create mode 100644 lang/python/gpg/constants/data/encoding.py create mode 100644 lang/python/gpg/constants/event.py create mode 100644 lang/python/gpg/constants/import.py create mode 100644 lang/python/gpg/constants/keylist/__init__.py create mode 100644 lang/python/gpg/constants/keylist/mode.py create mode 100644 lang/python/gpg/constants/md.py create mode 100644 lang/python/gpg/constants/pk.py create mode 100644 lang/python/gpg/constants/protocol.py create mode 100644 lang/python/gpg/constants/sig/__init__.py create mode 100644 lang/python/gpg/constants/sig/mode.py create mode 100644 lang/python/gpg/constants/sigsum.py create mode 100644 lang/python/gpg/constants/status.py create mode 100644 lang/python/gpg/constants/validity.py create mode 100644 lang/python/gpg/core.py create mode 100644 lang/python/gpg/errors.py create mode 100644 lang/python/gpg/results.py create mode 100644 lang/python/gpg/util.py create mode 100644 lang/python/gpg/version.py.in delete mode 100644 lang/python/pyme/__init__.py delete mode 100644 lang/python/pyme/callbacks.py delete mode 100644 lang/python/pyme/constants/__init__.py delete mode 100644 lang/python/pyme/constants/data/__init__.py delete mode 100644 lang/python/pyme/constants/data/encoding.py delete mode 100644 lang/python/pyme/constants/event.py delete mode 100644 lang/python/pyme/constants/import.py delete mode 100644 lang/python/pyme/constants/keylist/__init__.py delete mode 100644 lang/python/pyme/constants/keylist/mode.py delete mode 100644 lang/python/pyme/constants/md.py delete mode 100644 lang/python/pyme/constants/pk.py delete mode 100644 lang/python/pyme/constants/protocol.py delete mode 100644 lang/python/pyme/constants/sig/__init__.py delete mode 100644 lang/python/pyme/constants/sig/mode.py delete mode 100644 lang/python/pyme/constants/sigsum.py delete mode 100644 lang/python/pyme/constants/status.py delete mode 100644 lang/python/pyme/constants/validity.py delete mode 100644 lang/python/pyme/core.py delete mode 100644 lang/python/pyme/errors.py delete mode 100644 lang/python/pyme/results.py delete mode 100644 lang/python/pyme/util.py delete mode 100644 lang/python/pyme/version.py.in diff --git a/NEWS b/NEWS index 38f38d6d..2b71a6aa 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ Noteworthy changes in version 1.7.2 (unreleased) ------------------------------------------------ + * The module of the Python bindings has been renamed to 'gpg'. * Interface changes relative to the 1.7.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/configure.ac b/configure.ac index 617128ec..600e8ba7 100644 --- a/configure.ac +++ b/configure.ac @@ -885,7 +885,7 @@ AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpgme.asd]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([lang/qt/doc/Doxyfile])]) AC_CONFIG_FILES(lang/qt/doc/Makefile) AC_CONFIG_FILES([lang/python/Makefile - lang/python/pyme/version.py + lang/python/gpg/version.py lang/python/tests/Makefile]) AC_CONFIG_FILES([lang/python/setup.py], [chmod a+x lang/python/setup.py]) AC_OUTPUT diff --git a/lang/README b/lang/README index f7a15955..0c5bbd96 100644 --- a/lang/README +++ b/lang/README @@ -12,4 +12,4 @@ Directory Language cl Common Lisp cpp C++ qt Qt-Framework API -python Python 2 and 3 (port of PyME 0.9.0) +python Python 2 and 3 (module name: gpg) diff --git a/lang/python/MANIFEST.in b/lang/python/MANIFEST.in index eefdb83e..8f63640a 100644 --- a/lang/python/MANIFEST.in +++ b/lang/python/MANIFEST.in @@ -1,4 +1,4 @@ recursive-include examples *.py include gpgme-h-clean.py gpgme.i include helpers.c helpers.h private.h -recursive-include pyme *.py +recursive-include gpg *.py diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am index 224a91ad..e32fd125 100644 --- a/lang/python/Makefile.am +++ b/lang/python/Makefile.am @@ -23,7 +23,7 @@ EXTRA_DIST = \ helpers.c helpers.h private.h \ gpgme-h-clean.py \ examples \ - pyme + gpg SUBDIRS = . tests @@ -35,21 +35,21 @@ COPY_FILES = \ $(srcdir)/examples \ $(srcdir)/helpers.c $(srcdir)/helpers.h $(srcdir)/private.h -COPY_FILES_PYME = \ - $(srcdir)/pyme/callbacks.py \ - $(srcdir)/pyme/constants \ - $(srcdir)/pyme/core.py \ - $(srcdir)/pyme/errors.py \ - $(srcdir)/pyme/__init__.py \ - $(srcdir)/pyme/results.py \ - $(srcdir)/pyme/util.py +COPY_FILES_GPG = \ + $(srcdir)/gpg/callbacks.py \ + $(srcdir)/gpg/constants \ + $(srcdir)/gpg/core.py \ + $(srcdir)/gpg/errors.py \ + $(srcdir)/gpg/__init__.py \ + $(srcdir)/gpg/results.py \ + $(srcdir)/gpg/util.py # For VPATH builds we need to copy some files because Python's # distutils are not VPATH-aware. -copystamp: $(COPY_FILES) $(COPY_FILES_PYME) data.h config.h +copystamp: $(COPY_FILES) $(COPY_FILES_GPG) data.h config.h if test "$(srcdir)" != "$(builddir)" ; then \ cp -R $(COPY_FILES) . ; \ - cp -R $(COPY_FILES_PYME) pyme ; \ + cp -R $(COPY_FILES_GPG) gpg ; \ fi touch $@ @@ -65,22 +65,22 @@ all-local: copystamp $$PYTHON setup.py build --verbose ; \ done -dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc: copystamp +dist/gpg-$(VERSION).tar.gz dist/gpg-$(VERSION).tar.gz.asc: copystamp CFLAGS="$(CFLAGS)" \ $(PYTHON) setup.py sdist --verbose - gpg2 --detach-sign --armor dist/pyme3-$(VERSION).tar.gz + gpg2 --detach-sign --armor dist/gpg-$(VERSION).tar.gz .PHONY: prepare prepare: copystamp .PHONY: sdist -sdist: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc +sdist: dist/gpg-$(VERSION).tar.gz dist/gpg-$(VERSION).tar.gz.asc .PHONY: upload -upload: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc +upload: dist/gpg-$(VERSION).tar.gz dist/gpg-$(VERSION).tar.gz.asc twine upload $^ -CLEANFILES = gpgme.h errors.i gpgme_wrap.c pyme/gpgme.py \ +CLEANFILES = gpgme.h errors.i gpgme_wrap.c gpg/gpgme.py \ data.h config.h copystamp # Remove the rest. @@ -92,8 +92,8 @@ clean-local: if test "$(srcdir)" != "$(builddir)" ; then \ find . -type d ! -perm -200 -exec chmod u+w {} ';' ; \ for F in $(COPY_FILES); do rm -rf -- `basename $$F` ; done ; \ - for F in $(COPY_FILES_PYME); do \ - rm -rf -- pyme/`basename $$F` ; \ + for F in $(COPY_FILES_GPG); do \ + rm -rf -- gpg/`basename $$F` ; \ done ; \ fi @@ -107,9 +107,9 @@ install-exec-local: cat files.txt >> install_files.txt ; \ rm files.txt ; \ done - $(MKDIR_P) $(DESTDIR)$(pythondir)/pyme - mv install_files.txt $(DESTDIR)$(pythondir)/pyme + $(MKDIR_P) $(DESTDIR)$(pythondir)/gpg + mv install_files.txt $(DESTDIR)$(pythondir)/gpg uninstall-local: - xargs <$(DESTDIR)$(pythondir)/pyme/install_files.txt -- rm -rf -- - rm -rf -- $(DESTDIR)$(pythondir)/pyme + xargs <$(DESTDIR)$(pythondir)/gpg/install_files.txt -- rm -rf -- + rm -rf -- $(DESTDIR)$(pythondir)/gpg diff --git a/lang/python/README b/lang/python/README index 98c007e0..6a2e8b8c 100644 --- a/lang/python/README +++ b/lang/python/README @@ -1,10 +1,10 @@ -PyME - GPGME for Python -*- org -*- +gpg - GPGME bindings for Python -*- org -*- ======================= -PyME is a python interface to the GPGME library: +The "gpg" module is a python interface to the GPGME library: https://www.gnupg.org/related_software/gpgme/ -PyME offers two interfaces, one is a high-level, curated, and +"gpg" offers two interfaces, one is a high-level, curated, and idiomatic interface that is implemented as a shim on top of the low-level interface automatically created using SWIG. @@ -27,20 +27,22 @@ https://bugs.gnupg.org/gnupg/ * Authors -PyME has been created by John Goerzen, and maintained, developed, and +PyME was created by John Goerzen, and maintained, developed, and cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, and everyone who contributed to it in any way. In 2016 we merged a port of PyME to into the GPGME repository, and development will continue there. Please see the VCS history for the list of contributors, and if you do find bugs, or want to contribute, -please get in touch and help maintain PyME. +please get in touch and help maintain the python gpg bindings. Please see the section 'History' further down this document for references to previous versions. * History + - The python bindings were renamed from PyME to "gpg" in 2016. + - The bindings have been merged into the GPGME repository in 2016. - The latest version of PyME for Python 3.2 and above (as of diff --git a/lang/python/docs/Short_History.rst b/lang/python/docs/Short_History.rst index 126c1218..8f609272 100644 --- a/lang/python/docs/Short_History.rst +++ b/lang/python/docs/Short_History.rst @@ -1,6 +1,6 @@ -======================= -A Short History of PyME -======================= +========================================== +A Short History of gpg bindings for Python +========================================== In 2002 John Goerzen released PyME; Python bindings for the GPGME module which utilised the current release of Python of the time @@ -27,6 +27,8 @@ decision to fold the Python 3 port back into the original GPGME release in the languages subdirectory for non-C bindings. Ben is the maintainer of the Python 3 port within GPGME. +In 2016 PyME was renamed to "gpg" and adopted by the upstream GnuPG +team. --------------------- The Annoyances of Git diff --git a/lang/python/examples/assuan.py b/lang/python/examples/assuan.py index 22960d31..f02cd166 100644 --- a/lang/python/examples/assuan.py +++ b/lang/python/examples/assuan.py @@ -20,9 +20,9 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme +import gpg -with pyme.Context(protocol=pyme.constants.PROTOCOL_ASSUAN) as c: +with gpg.Context(protocol=gpg.constants.PROTOCOL_ASSUAN) as c: # Invoke the pinentry to get a confirmation. err = c.assuan_transact(['GET_CONFIRMATION', 'Hello there']) print("You chose {}.".format("cancel" if err else "ok")) diff --git a/lang/python/examples/decryption-filter.py b/lang/python/examples/decryption-filter.py index 3007c2b0..987dfd13 100644 --- a/lang/python/examples/decryption-filter.py +++ b/lang/python/examples/decryption-filter.py @@ -17,7 +17,7 @@ """A decryption filter -This demonstrates decryption using pyme3 in three lines of code. To +This demonstrates decryption using gpg3 in three lines of code. To be used like this: ./decryption-filter.py message.plain @@ -28,5 +28,5 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme -pyme.Context().decrypt(sys.stdin, sink=sys.stdout) +import gpg +gpg.Context().decrypt(sys.stdin, sink=sys.stdout) diff --git a/lang/python/examples/delkey.py b/lang/python/examples/delkey.py index a02f4129..12510f3e 100755 --- a/lang/python/examples/delkey.py +++ b/lang/python/examples/delkey.py @@ -22,12 +22,12 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme +import gpg -with pyme.Context() as c: +with gpg.Context() as c: # Note: We must not modify the key store during iteration, # therefore, we explicitly make a list. - keys = list(c.keylist("joe+pyme@example.org")) + keys = list(c.keylist("joe+gpg@example.org")) for k in keys: c.op_delete(k, True) diff --git a/lang/python/examples/encrypt-to-all.py b/lang/python/examples/encrypt-to-all.py index 35873bde..bad4220c 100755 --- a/lang/python/examples/encrypt-to-all.py +++ b/lang/python/examples/encrypt-to-all.py @@ -26,9 +26,9 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme +import gpg -with pyme.Context(armor=True) as c: +with gpg.Context(armor=True) as c: recipients = list() for key in c.keylist(): valid = 0 @@ -42,7 +42,7 @@ with pyme.Context(armor=True) as c: try: ciphertext, _, _ = c.encrypt(b'This is my message.', recipients=recipients) - except pyme.errors.InvalidRecipients as e: + except gpg.errors.InvalidRecipients as e: print("Encryption failed for these keys:\n{0!s}".format(e)) # filter out the bad keys diff --git a/lang/python/examples/exportimport.py b/lang/python/examples/exportimport.py index bc946bc4..8ae87a8c 100755 --- a/lang/python/examples/exportimport.py +++ b/lang/python/examples/exportimport.py @@ -17,18 +17,18 @@ # along with this program; if not, see . # Sample of export and import of keys -# It uses keys for joe+pyme@example.org generated by genkey.py script +# It uses keys for joe+gpg@example.org generated by genkey.py script from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys import os -import pyme +import gpg -user = "joe+pyme@example.org" +user = "joe+gpg@example.org" -with pyme.Context(armor=True) as c, pyme.Data() as expkey: +with gpg.Context(armor=True) as c, gpg.Data() as expkey: print(" - Export %s's public keys - " % user) c.op_export(user, 0, expkey) @@ -43,7 +43,7 @@ with pyme.Context(armor=True) as c, pyme.Data() as expkey: # delete keys to ensure that they came from our imported data. Note # that if joe's key has private part as well we can only delete both # of them. -with pyme.Context() as c: +with gpg.Context() as c: # Note: We must not modify the key store during iteration, # therfore, we explicitly make a list. keys = list(c.keylist(user)) @@ -51,7 +51,7 @@ with pyme.Context() as c: for k in keys: c.op_delete(k, True) -with pyme.Context() as c: +with gpg.Context() as c: print(" - Import exported keys - ") c.op_import(expstring) result = c.op_import_result() diff --git a/lang/python/examples/genkey.py b/lang/python/examples/genkey.py index ee70303d..a043500e 100755 --- a/lang/python/examples/genkey.py +++ b/lang/python/examples/genkey.py @@ -20,7 +20,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme +import gpg # This is the example from the GPGME manual. @@ -31,14 +31,14 @@ Subkey-Type: RSA Subkey-Length: 2048 Name-Real: Joe Tester Name-Comment: with stupid passphrase -Name-Email: joe+pyme@example.org +Name-Email: joe+gpg@example.org Passphrase: Crypt0R0cks Expire-Date: 2020-12-31 """ -with pyme.Context() as c: - c.set_progress_cb(pyme.callbacks.progress_stdout) +with gpg.Context() as c: + c.set_progress_cb(gpg.callbacks.progress_stdout) c.op_genkey(parms, None, None) print("Generated key with fingerprint {0}.".format( c.op_genkey_result().fpr)) diff --git a/lang/python/examples/inter-edit.py b/lang/python/examples/inter-edit.py index 3c0f29ba..ed0d8c42 100644 --- a/lang/python/examples/inter-edit.py +++ b/lang/python/examples/inter-edit.py @@ -22,14 +22,14 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme +import gpg if len(sys.argv) != 2: sys.exit("Usage: %s \n" % sys.argv[0]) name = sys.argv[1] -with pyme.Context() as c: +with gpg.Context() as c: keys = list(c.keylist(name)) if len(keys) == 0: sys.exit("No key matching {}.".format(name)) diff --git a/lang/python/examples/sign.py b/lang/python/examples/sign.py index 2f235baf..16c2256a 100755 --- a/lang/python/examples/sign.py +++ b/lang/python/examples/sign.py @@ -20,9 +20,9 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme -from pyme.constants.sig import mode +import gpg +from gpg.constants.sig import mode -with pyme.Context() as c: +with gpg.Context() as c: signed, _ = c.sign(b"Test message", mode=mode.CLEAR) sys.stdout.buffer.write(signed) diff --git a/lang/python/examples/signverify.py b/lang/python/examples/signverify.py index 03bc0a64..5870ca95 100755 --- a/lang/python/examples/signverify.py +++ b/lang/python/examples/signverify.py @@ -17,18 +17,18 @@ # along with this program; if not, see . # Sample of unattended signing/verifying of a message. -# It uses keys for joe+pyme@example.org generated by genkey.py script +# It uses keys for joe+gpg@example.org generated by genkey.py script from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme -from pyme.constants.sig import mode +import gpg +from gpg.constants.sig import mode -user = "joe+pyme" +user = "joe+gpg" -with pyme.Context(pinentry_mode=pyme.constants.PINENTRY_MODE_LOOPBACK) as c: +with gpg.Context(pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK) as c: keys = list(c.keylist(user)) if len(keys) == 0: sys.exit("No key matching {}.".format(user)) diff --git a/lang/python/examples/simple.py b/lang/python/examples/simple.py index 5598487b..8f451d7c 100755 --- a/lang/python/examples/simple.py +++ b/lang/python/examples/simple.py @@ -21,9 +21,9 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme +import gpg -with pyme.Context(armor=True) as c: +with gpg.Context(armor=True) as c: recipients = [] print("Enter name of your recipient(s), end with a blank line.") while True: diff --git a/lang/python/examples/testCMSgetkey.py b/lang/python/examples/testCMSgetkey.py index 62c35d26..0f02cb1b 100644 --- a/lang/python/examples/testCMSgetkey.py +++ b/lang/python/examples/testCMSgetkey.py @@ -22,12 +22,12 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme +import gpg if len(sys.argv) != 2: sys.exit("fingerprint or unique key ID for gpgme_get_key()") -with pyme.Context(protocol=pyme.constants.PROTOCOL_CMS) as c: +with gpg.Context(protocol=gpg.constants.PROTOCOL_CMS) as c: key = c.get_key(sys.argv[1]) print("got key: ", key.subkeys[0].fpr) diff --git a/lang/python/examples/verifydetails.py b/lang/python/examples/verifydetails.py index 81f82e99..0d2b72cb 100755 --- a/lang/python/examples/verifydetails.py +++ b/lang/python/examples/verifydetails.py @@ -21,8 +21,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -from pyme import core -from pyme.constants import protocol +from gpg import core +from gpg.constants import protocol def print_engine_infos(): print("gpgme version:", core.check_version(None)) diff --git a/lang/python/gpg/__init__.py b/lang/python/gpg/__init__.py new file mode 100644 index 00000000..385b17e3 --- /dev/null +++ b/lang/python/gpg/__init__.py @@ -0,0 +1,121 @@ +# Copyright (C) 2016 g10 Code GmbH +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +"""gpg: GnuPG Interface for Python (GPGME bindings) + +Welcome to gpg, the GnuPG Interface for Python. + +The latest release of this package may be obtained from +https://www.gnupg.org + +FEATURES +-------- + + * Feature-rich, full implementation of the GPGME library. Supports + all GPGME features. Callback functions may be written in pure + Python. Exceptions raised in callbacks are properly propagated. + + * Ability to sign, encrypt, decrypt, and verify data. + + * Ability to list keys, export and import keys, and manage the keyring. + + * Fully object-oriented with convenient classes and modules. + +QUICK EXAMPLE +------------- + + >>> import gpg + >>> with gpg.Context() as c: + >>> with gpg.Context() as c: + ... cipher, _, _ = c.encrypt("Hello world :)".encode(), + ... passphrase="abc") + ... c.decrypt(cipher, passphrase="abc") + ... + (b'Hello world :)', + , + ) + +GENERAL OVERVIEW +---------------- + +For those of you familiar with GPGME, you will be right at home here. + +The python gpg module is, for the most part, a direct interface to the C GPGME +library. However, it is re-packaged in a more Pythonic way -- +object-oriented with classes and modules. Take a look at the classes +defined here -- they correspond directly to certain object types in GPGME +for C. For instance, the following C code: + +gpgme_ctx_t context; +gpgme_new(&context); +... +gpgme_op_encrypt(context, recp, 1, plain, cipher); + +Translates into the following Python code: + +context = core.Context() +... +context.op_encrypt(recp, 1, plain, cipher) + +The Python module automatically does error-checking and raises Python +exception gpg.errors.GPGMEError when GPGME signals an error. getcode() +and getsource() of this exception return code and source of the error. + +IMPORTANT NOTE +-------------- +This documentation only covers a small subset of available GPGME functions and +methods. Please consult the documentation for the C library +for comprehensive coverage. + +This library uses Python's reflection to automatically detect the methods +that are available for each class, and as such, most of those methods +do not appear explicitly anywhere. You can use dir() python built-in command +on an object to see what methods and fields it has but their meaning can +be found only in GPGME documentation. + +FOR MORE INFORMATION +-------------------- +GnuPG homepage: https://www.gnupg.org/ +GPGME documentation: https://www.gnupg.org/documentation/manuals/gpgme/ + +""" + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from . import core +from . import errors +from . import constants +from . import util +from . import callbacks +from . import version +from .core import Context +from .core import Data + +# Interface hygiene. + +# Drop the low-level gpgme that creeps in for some reason. +gpgme = None +del gpgme + +# This is a white-list of symbols. Any other will alert pyflakes. +_ = [Context, Data, core, errors, constants, util, callbacks, version] +del _ + +__all__ = ["Context", "Data", + "core", "errors", "constants", "util", "callbacks", "version"] diff --git a/lang/python/gpg/callbacks.py b/lang/python/gpg/callbacks.py new file mode 100644 index 00000000..b25a9a74 --- /dev/null +++ b/lang/python/gpg/callbacks.py @@ -0,0 +1,49 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from getpass import getpass + +def passphrase_stdin(hint, desc, prev_bad, hook=None): + """This is a sample callback that will read a passphrase from + the terminal. The hook here, if present, will be used to describe + why the passphrase is needed.""" + why = '' + if hook != None: + why = ' ' + hook + if prev_bad: + why += ' (again)' + print("Please supply %s' password%s:" % (hint, why)) + return getpass() + +def progress_stdout(what, type, current, total, hook=None): + print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\ + (what, type, current, total)) + +def readcb_fh(count, hook): + """A callback for data. hook should be a Python file-like object.""" + if count: + # Should return '' on EOF + return hook.read(count) + else: + # Wants to rewind. + if not hasattr(hook, 'seek'): + return None + hook.seek(0, 0) + return None diff --git a/lang/python/gpg/constants/__init__.py b/lang/python/gpg/constants/__init__.py new file mode 100644 index 00000000..c6fa102e --- /dev/null +++ b/lang/python/gpg/constants/__init__.py @@ -0,0 +1,114 @@ + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_', globals()) + +__all__ = ['data', 'event', 'import', 'keylist', 'md', 'pk', + 'protocol', 'sig', 'sigsum', 'status', 'validity'] + +# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We +# implement gpg.Context.op_edit using gpgme_op_interact, so the +# callbacks will be called with string keywords instead of numeric +# status messages. Code that is using these constants will continue +# to work. + +STATUS_ABORT = "ABORT" +STATUS_ALREADY_SIGNED = "ALREADY_SIGNED" +STATUS_ATTRIBUTE = "ATTRIBUTE" +STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED" +STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE" +STATUS_BADARMOR = "BADARMOR" +STATUS_BADMDC = "BADMDC" +STATUS_BADSIG = "BADSIG" +STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION" +STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION" +STATUS_BEGIN_SIGNING = "BEGIN_SIGNING" +STATUS_BEGIN_STREAM = "BEGIN_STREAM" +STATUS_CARDCTRL = "CARDCTRL" +STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED" +STATUS_DECRYPTION_INFO = "DECRYPTION_INFO" +STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY" +STATUS_DELETE_PROBLEM = "DELETE_PROBLEM" +STATUS_ENC_TO = "ENC_TO" +STATUS_END_DECRYPTION = "END_DECRYPTION" +STATUS_END_ENCRYPTION = "END_ENCRYPTION" +STATUS_END_STREAM = "END_STREAM" +STATUS_ENTER = "ENTER" +STATUS_ERRMDC = "ERRMDC" +STATUS_ERROR = "ERROR" +STATUS_ERRSIG = "ERRSIG" +STATUS_EXPKEYSIG = "EXPKEYSIG" +STATUS_EXPSIG = "EXPSIG" +STATUS_FAILURE = "FAILURE" +STATUS_FILE_DONE = "FILE_DONE" +STATUS_FILE_ERROR = "FILE_ERROR" +STATUS_FILE_START = "FILE_START" +STATUS_GET_BOOL = "GET_BOOL" +STATUS_GET_HIDDEN = "GET_HIDDEN" +STATUS_GET_LINE = "GET_LINE" +STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE" +STATUS_GOODMDC = "GOODMDC" +STATUS_GOODSIG = "GOODSIG" +STATUS_GOT_IT = "GOT_IT" +STATUS_IMPORT_OK = "IMPORT_OK" +STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM" +STATUS_IMPORT_RES = "IMPORT_RES" +STATUS_IMPORTED = "IMPORTED" +STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN" +STATUS_INV_RECP = "INV_RECP" +STATUS_INV_SGNR = "INV_SGNR" +STATUS_KEY_CONSIDERED = "KEY_CONSIDERED" +STATUS_KEY_CREATED = "KEY_CREATED" +STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED" +STATUS_KEYEXPIRED = "KEYEXPIRED" +STATUS_KEYREVOKED = "KEYREVOKED" +STATUS_LEAVE = "LEAVE" +STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE" +STATUS_MOUNTPOINT = "MOUNTPOINT" +STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE" +STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN" +STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM" +STATUS_NEWSIG = "NEWSIG" +STATUS_NO_PUBKEY = "NO_PUBKEY" +STATUS_NO_RECP = "NO_RECP" +STATUS_NO_SECKEY = "NO_SECKEY" +STATUS_NO_SGNR = "NO_SGNR" +STATUS_NODATA = "NODATA" +STATUS_NOTATION_DATA = "NOTATION_DATA" +STATUS_NOTATION_FLAGS = "NOTATION_FLAGS" +STATUS_NOTATION_NAME = "NOTATION_NAME" +STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED" +STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD" +STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD" +STATUS_PLAINTEXT = "PLAINTEXT" +STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH" +STATUS_POLICY_URL = "POLICY_URL" +STATUS_PROGRESS = "PROGRESS" +STATUS_REVKEYSIG = "REVKEYSIG" +STATUS_RSA_OR_IDEA = "RSA_OR_IDEA" +STATUS_SC_OP_FAILURE = "SC_OP_FAILURE" +STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS" +STATUS_SESSION_KEY = "SESSION_KEY" +STATUS_SHM_GET = "SHM_GET" +STATUS_SHM_GET_BOOL = "SHM_GET_BOOL" +STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN" +STATUS_SHM_INFO = "SHM_INFO" +STATUS_SIG_CREATED = "SIG_CREATED" +STATUS_SIG_ID = "SIG_ID" +STATUS_SIG_SUBPACKET = "SIG_SUBPACKET" +STATUS_SIGEXPIRED = "SIGEXPIRED" +STATUS_SUCCESS = "SUCCESS" +STATUS_TOFU_STATS = "TOFU_STATS" +STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG" +STATUS_TOFU_USER = "TOFU_USER" +STATUS_TRUNCATED = "TRUNCATED" +STATUS_TRUST_FULLY = "TRUST_FULLY" +STATUS_TRUST_MARGINAL = "TRUST_MARGINAL" +STATUS_TRUST_NEVER = "TRUST_NEVER" +STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE" +STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED" +STATUS_UNEXPECTED = "UNEXPECTED" +STATUS_USERID_HINT = "USERID_HINT" +STATUS_VALIDSIG = "VALIDSIG" diff --git a/lang/python/gpg/constants/data/__init__.py b/lang/python/gpg/constants/data/__init__.py new file mode 100644 index 00000000..8274ab91 --- /dev/null +++ b/lang/python/gpg/constants/data/__init__.py @@ -0,0 +1,6 @@ + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from . import encoding +__all__ = ['encoding'] diff --git a/lang/python/gpg/constants/data/encoding.py b/lang/python/gpg/constants/data/encoding.py new file mode 100644 index 00000000..fc7c6b22 --- /dev/null +++ b/lang/python/gpg/constants/data/encoding.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_DATA_ENCODING_', globals()) diff --git a/lang/python/gpg/constants/event.py b/lang/python/gpg/constants/event.py new file mode 100644 index 00000000..11e63f09 --- /dev/null +++ b/lang/python/gpg/constants/event.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_EVENT_', globals()) diff --git a/lang/python/gpg/constants/import.py b/lang/python/gpg/constants/import.py new file mode 100644 index 00000000..4a65a306 --- /dev/null +++ b/lang/python/gpg/constants/import.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_IMPORT_', globals()) diff --git a/lang/python/gpg/constants/keylist/__init__.py b/lang/python/gpg/constants/keylist/__init__.py new file mode 100644 index 00000000..2ce0edfd --- /dev/null +++ b/lang/python/gpg/constants/keylist/__init__.py @@ -0,0 +1,6 @@ + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from . import mode +__all__ = ['mode'] diff --git a/lang/python/gpg/constants/keylist/mode.py b/lang/python/gpg/constants/keylist/mode.py new file mode 100644 index 00000000..0939c6ca --- /dev/null +++ b/lang/python/gpg/constants/keylist/mode.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_KEYLIST_MODE_', globals()) diff --git a/lang/python/gpg/constants/md.py b/lang/python/gpg/constants/md.py new file mode 100644 index 00000000..7a04849e --- /dev/null +++ b/lang/python/gpg/constants/md.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_MD_', globals()) diff --git a/lang/python/gpg/constants/pk.py b/lang/python/gpg/constants/pk.py new file mode 100644 index 00000000..b2ece88d --- /dev/null +++ b/lang/python/gpg/constants/pk.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_PK_', globals()) diff --git a/lang/python/gpg/constants/protocol.py b/lang/python/gpg/constants/protocol.py new file mode 100644 index 00000000..562042e9 --- /dev/null +++ b/lang/python/gpg/constants/protocol.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_PROTOCOL_', globals()) diff --git a/lang/python/gpg/constants/sig/__init__.py b/lang/python/gpg/constants/sig/__init__.py new file mode 100644 index 00000000..2ce0edfd --- /dev/null +++ b/lang/python/gpg/constants/sig/__init__.py @@ -0,0 +1,6 @@ + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from . import mode +__all__ = ['mode'] diff --git a/lang/python/gpg/constants/sig/mode.py b/lang/python/gpg/constants/sig/mode.py new file mode 100644 index 00000000..f53d7ed0 --- /dev/null +++ b/lang/python/gpg/constants/sig/mode.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_SIG_MODE_', globals()) diff --git a/lang/python/gpg/constants/sigsum.py b/lang/python/gpg/constants/sigsum.py new file mode 100644 index 00000000..2a7f2c06 --- /dev/null +++ b/lang/python/gpg/constants/sigsum.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_SIGSUM_', globals()) diff --git a/lang/python/gpg/constants/status.py b/lang/python/gpg/constants/status.py new file mode 100644 index 00000000..a0ad073e --- /dev/null +++ b/lang/python/gpg/constants/status.py @@ -0,0 +1,124 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We +# implement gpg.Context.op_edit using gpgme_op_interact, so the +# callbacks will be called with string keywords instead of numeric +# status messages. Code that is using these constants will continue +# to work. + +ABORT = "ABORT" +ALREADY_SIGNED = "ALREADY_SIGNED" +ATTRIBUTE = "ATTRIBUTE" +BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED" +BAD_PASSPHRASE = "BAD_PASSPHRASE" +BADARMOR = "BADARMOR" +BADMDC = "BADMDC" +BADSIG = "BADSIG" +BEGIN_DECRYPTION = "BEGIN_DECRYPTION" +BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION" +BEGIN_SIGNING = "BEGIN_SIGNING" +BEGIN_STREAM = "BEGIN_STREAM" +CARDCTRL = "CARDCTRL" +DECRYPTION_FAILED = "DECRYPTION_FAILED" +DECRYPTION_INFO = "DECRYPTION_INFO" +DECRYPTION_OKAY = "DECRYPTION_OKAY" +DELETE_PROBLEM = "DELETE_PROBLEM" +ENC_TO = "ENC_TO" +END_DECRYPTION = "END_DECRYPTION" +END_ENCRYPTION = "END_ENCRYPTION" +END_STREAM = "END_STREAM" +ENTER = "ENTER" +ERRMDC = "ERRMDC" +ERROR = "ERROR" +ERRSIG = "ERRSIG" +EXPKEYSIG = "EXPKEYSIG" +EXPSIG = "EXPSIG" +FAILURE = "FAILURE" +FILE_DONE = "FILE_DONE" +FILE_ERROR = "FILE_ERROR" +FILE_START = "FILE_START" +GET_BOOL = "GET_BOOL" +GET_HIDDEN = "GET_HIDDEN" +GET_LINE = "GET_LINE" +GOOD_PASSPHRASE = "GOOD_PASSPHRASE" +GOODMDC = "GOODMDC" +GOODSIG = "GOODSIG" +GOT_IT = "GOT_IT" +IMPORT_OK = "IMPORT_OK" +IMPORT_PROBLEM = "IMPORT_PROBLEM" +IMPORT_RES = "IMPORT_RES" +IMPORTED = "IMPORTED" +INQUIRE_MAXLEN = "INQUIRE_MAXLEN" +INV_RECP = "INV_RECP" +INV_SGNR = "INV_SGNR" +KEY_CONSIDERED = "KEY_CONSIDERED" +KEY_CREATED = "KEY_CREATED" +KEY_NOT_CREATED = "KEY_NOT_CREATED" +KEYEXPIRED = "KEYEXPIRED" +KEYREVOKED = "KEYREVOKED" +LEAVE = "LEAVE" +MISSING_PASSPHRASE = "MISSING_PASSPHRASE" +MOUNTPOINT = "MOUNTPOINT" +NEED_PASSPHRASE = "NEED_PASSPHRASE" +NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN" +NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM" +NEWSIG = "NEWSIG" +NO_PUBKEY = "NO_PUBKEY" +NO_RECP = "NO_RECP" +NO_SECKEY = "NO_SECKEY" +NO_SGNR = "NO_SGNR" +NODATA = "NODATA" +NOTATION_DATA = "NOTATION_DATA" +NOTATION_FLAGS = "NOTATION_FLAGS" +NOTATION_NAME = "NOTATION_NAME" +PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED" +PKA_TRUST_BAD = "PKA_TRUST_BAD" +PKA_TRUST_GOOD = "PKA_TRUST_GOOD" +PLAINTEXT = "PLAINTEXT" +PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH" +POLICY_URL = "POLICY_URL" +PROGRESS = "PROGRESS" +REVKEYSIG = "REVKEYSIG" +RSA_OR_IDEA = "RSA_OR_IDEA" +SC_OP_FAILURE = "SC_OP_FAILURE" +SC_OP_SUCCESS = "SC_OP_SUCCESS" +SESSION_KEY = "SESSION_KEY" +SHM_GET = "SHM_GET" +SHM_GET_BOOL = "SHM_GET_BOOL" +SHM_GET_HIDDEN = "SHM_GET_HIDDEN" +SHM_INFO = "SHM_INFO" +SIG_CREATED = "SIG_CREATED" +SIG_ID = "SIG_ID" +SIG_SUBPACKET = "SIG_SUBPACKET" +SIGEXPIRED = "SIGEXPIRED" +SUCCESS = "SUCCESS" +TOFU_STATS = "TOFU_STATS" +TOFU_STATS_LONG = "TOFU_STATS_LONG" +TOFU_USER = "TOFU_USER" +TRUNCATED = "TRUNCATED" +TRUST_FULLY = "TRUST_FULLY" +TRUST_MARGINAL = "TRUST_MARGINAL" +TRUST_NEVER = "TRUST_NEVER" +TRUST_ULTIMATE = "TRUST_ULTIMATE" +TRUST_UNDEFINED = "TRUST_UNDEFINED" +UNEXPECTED = "UNEXPECTED" +USERID_HINT = "USERID_HINT" +VALIDSIG = "VALIDSIG" diff --git a/lang/python/gpg/constants/validity.py b/lang/python/gpg/constants/validity.py new file mode 100644 index 00000000..da14ca42 --- /dev/null +++ b/lang/python/gpg/constants/validity.py @@ -0,0 +1,22 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from gpg import util +util.process_constants('GPGME_VALIDITY_', globals()) diff --git a/lang/python/gpg/core.py b/lang/python/gpg/core.py new file mode 100644 index 00000000..748bcbb9 --- /dev/null +++ b/lang/python/gpg/core.py @@ -0,0 +1,1164 @@ +# Copyright (C) 2016 g10 Code GmbH +# Copyright (C) 2004,2008 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +"""Core functionality + +Core functionality of GPGME wrapped in a object-oriented fashion. +Provides the 'Context' class for performing cryptographic operations, +and the 'Data' class describing buffers of data. + +""" + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import re +import os +import warnings +import weakref +from . import gpgme +from .errors import errorcheck, GPGMEError +from . import constants +from . import errors +from . import util + +class GpgmeWrapper(object): + """Base wrapper class + + Not to be instantiated directly. + + """ + + def __init__(self, wrapped): + self._callback_excinfo = None + self.wrapped = wrapped + + def __repr__(self): + return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(), + self.wrapped) + + def __str__(self): + acc = ['{}.{}'.format(__name__, self.__class__.__name__)] + flags = [f for f in self._boolean_properties if getattr(self, f)] + if flags: + acc.append('({})'.format(' '.join(flags))) + + return '<{}>'.format(' '.join(acc)) + + def __hash__(self): + return hash(repr(self.wrapped)) + + def __eq__(self, other): + if other == None: + return False + else: + return repr(self.wrapped) == repr(other.wrapped) + + @property + def _ctype(self): + """The name of the c type wrapped by this class + + Must be set by child classes. + + """ + raise NotImplementedError() + + @property + def _cprefix(self): + """The common prefix of c functions wrapped by this class + + Must be set by child classes. + + """ + raise NotImplementedError() + + def _errorcheck(self, name): + """Must be implemented by child classes. + + This function must return a trueish value for all c functions + returning gpgme_error_t.""" + raise NotImplementedError() + + """The set of all boolean properties""" + _boolean_properties = set() + + def __wrap_boolean_property(self, key, do_set=False, value=None): + get_func = getattr(gpgme, + "{}get_{}".format(self._cprefix, key)) + set_func = getattr(gpgme, + "{}set_{}".format(self._cprefix, key)) + def get(slf): + return bool(get_func(slf.wrapped)) + def set_(slf, value): + set_func(slf.wrapped, bool(value)) + + p = property(get, set_, doc="{} flag".format(key)) + setattr(self.__class__, key, p) + + if do_set: + set_(self, bool(value)) + else: + return get(self) + + _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)') + def __getattr__(self, key): + """On-the-fly generation of wrapper methods and properties""" + if key[0] == '_' or self._cprefix == None: + return None + + if key in self._boolean_properties: + return self.__wrap_boolean_property(key) + + name = self._cprefix + key + func = getattr(gpgme, name) + + if self._errorcheck(name): + def _funcwrap(slf, *args): + result = func(slf.wrapped, *args) + if slf._callback_excinfo: + gpgme.gpg_raise_callback_exception(slf) + return errorcheck(result, "Invocation of " + name) + else: + def _funcwrap(slf, *args): + result = func(slf.wrapped, *args) + if slf._callback_excinfo: + gpgme.gpg_raise_callback_exception(slf) + return result + + doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__")) + _funcwrap.__doc__ = doc + + # Monkey-patch the class. + setattr(self.__class__, key, _funcwrap) + + # Bind the method to 'self'. + def wrapper(*args): + return _funcwrap(self, *args) + wrapper.__doc__ = doc + + return wrapper + + def __setattr__(self, key, value): + """On-the-fly generation of properties""" + if key in self._boolean_properties: + self.__wrap_boolean_property(key, True, value) + else: + super(GpgmeWrapper, self).__setattr__(key, value) + +class Context(GpgmeWrapper): + """Context for cryptographic operations + + All cryptographic operations in GPGME are performed within a + context, which contains the internal state of the operation as + well as configuration parameters. By using several contexts you + can run several cryptographic operations in parallel, with + different configuration. + + Access to a context must be synchronized. + + """ + + def __init__(self, armor=False, textmode=False, offline=False, + signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT, + protocol=constants.PROTOCOL_OpenPGP, + wrapped=None): + """Construct a context object + + Keyword arguments: + armor -- enable ASCII armoring (default False) + textmode -- enable canonical text mode (default False) + offline -- do not contact external key sources (default False) + signers -- list of keys used for signing (default []) + pinentry_mode -- pinentry mode (default PINENTRY_MODE_DEFAULT) + protocol -- protocol to use (default PROTOCOL_OpenPGP) + + """ + if wrapped: + self.own = False + else: + tmp = gpgme.new_gpgme_ctx_t_p() + errorcheck(gpgme.gpgme_new(tmp)) + wrapped = gpgme.gpgme_ctx_t_p_value(tmp) + gpgme.delete_gpgme_ctx_t_p(tmp) + self.own = True + super(Context, self).__init__(wrapped) + self.armor = armor + self.textmode = textmode + self.offline = offline + self.signers = signers + self.pinentry_mode = pinentry_mode + self.protocol = protocol + + def encrypt(self, plaintext, recipients=[], sign=True, sink=None, + passphrase=None, always_trust=False, add_encrypt_to=False, + prepare=False, expect_sign=False, compress=True): + """Encrypt data + + Encrypt the given plaintext for the given recipients. If the + list of recipients is empty, the data is encrypted + symmetrically with a passphrase. + + The passphrase can be given as parameter, using a callback + registered at the context, or out-of-band via pinentry. + + Keyword arguments: + recipients -- list of keys to encrypt to + sign -- sign plaintext (default True) + sink -- write result to sink instead of returning it + passphrase -- for symmetric encryption + always_trust -- always trust the keys (default False) + add_encrypt_to -- encrypt to configured additional keys (default False) + prepare -- (ui) prepare for encryption (default False) + expect_sign -- (ui) prepare for signing (default False) + compress -- compress plaintext (default True) + + Returns: + ciphertext -- the encrypted data (or None if sink is given) + result -- additional information about the encryption + sign_result -- additional information about the signature(s) + + Raises: + InvalidRecipients -- if encryption using a particular key failed + InvalidSigners -- if signing using a particular key failed + GPGMEError -- as signaled by the underlying library + + """ + ciphertext = sink if sink else Data() + flags = 0 + flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST + flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO + flags |= prepare * constants.ENCRYPT_PREPARE + flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN + flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS + + if passphrase != None: + old_pinentry_mode = self.pinentry_mode + old_passphrase_cb = getattr(self, '_passphrase_cb', None) + self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK + def passphrase_cb(hint, desc, prev_bad, hook=None): + return passphrase + self.set_passphrase_cb(passphrase_cb) + + try: + if sign: + self.op_encrypt_sign(recipients, flags, plaintext, ciphertext) + else: + self.op_encrypt(recipients, flags, plaintext, ciphertext) + except errors.GPGMEError as e: + if e.getcode() == errors.UNUSABLE_PUBKEY: + result = self.op_encrypt_result() + if result.invalid_recipients: + raise errors.InvalidRecipients(result.invalid_recipients) + if e.getcode() == errors.UNUSABLE_SECKEY: + sig_result = self.op_sign_result() + if sig_result.invalid_signers: + raise errors.InvalidSigners(sig_result.invalid_signers) + raise + finally: + if passphrase != None: + self.pinentry_mode = old_pinentry_mode + if old_passphrase_cb: + self.set_passphrase_cb(*old_passphrase_cb[1:]) + + result = self.op_encrypt_result() + assert not result.invalid_recipients + sig_result = self.op_sign_result() if sign else None + assert not sig_result or not sig_result.invalid_signers + + cipherbytes = None + if not sink: + ciphertext.seek(0, os.SEEK_SET) + cipherbytes = ciphertext.read() + return cipherbytes, result, sig_result + + def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True): + """Decrypt data + + Decrypt the given ciphertext and verify any signatures. If + VERIFY is an iterable of keys, the ciphertext must be signed + by all those keys, otherwise an error is raised. + + If the ciphertext is symmetrically encrypted using a + passphrase, that passphrase can be given as parameter, using a + callback registered at the context, or out-of-band via + pinentry. + + Keyword arguments: + sink -- write result to sink instead of returning it + passphrase -- for symmetric decryption + verify -- check signatures (default True) + + Returns: + plaintext -- the decrypted data (or None if sink is given) + result -- additional information about the decryption + verify_result -- additional information about the signature(s) + + Raises: + UnsupportedAlgorithm -- if an unsupported algorithm was used + BadSignatures -- if a bad signature is encountered + MissingSignatures -- if expected signatures are missing or bad + GPGMEError -- as signaled by the underlying library + + """ + plaintext = sink if sink else Data() + + if passphrase != None: + old_pinentry_mode = self.pinentry_mode + old_passphrase_cb = getattr(self, '_passphrase_cb', None) + self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK + def passphrase_cb(hint, desc, prev_bad, hook=None): + return passphrase + self.set_passphrase_cb(passphrase_cb) + + try: + if verify: + self.op_decrypt_verify(ciphertext, plaintext) + else: + self.op_decrypt(ciphertext, plaintext) + finally: + if passphrase != None: + self.pinentry_mode = old_pinentry_mode + if old_passphrase_cb: + self.set_passphrase_cb(*old_passphrase_cb[1:]) + + result = self.op_decrypt_result() + verify_result = self.op_verify_result() if verify else None + if result.unsupported_algorithm: + raise errors.UnsupportedAlgorithm(result.unsupported_algorithm) + + if verify: + if any(s.status != errors.NO_ERROR + for s in verify_result.signatures): + raise errors.BadSignatures(verify_result) + + if verify and verify != True: + missing = list() + for key in verify: + ok = False + for subkey in key.subkeys: + for sig in verify_result.signatures: + if sig.summary & constants.SIGSUM_VALID == 0: + continue + if subkey.can_sign and subkey.fpr == sig.fpr: + ok = True + break + if ok: + break + if not ok: + missing.append(key) + if missing: + raise errors.MissingSignatures(verify_result, missing) + + plainbytes = None + if not sink: + plaintext.seek(0, os.SEEK_SET) + plainbytes = plaintext.read() + return plainbytes, result, verify_result + + def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL): + """Sign data + + Sign the given data with either the configured default local + key, or the 'signers' keys of this context. + + Keyword arguments: + mode -- signature mode (default: normal, see below) + sink -- write result to sink instead of returning it + + Returns: + either + signed_data -- encoded data and signature (normal mode) + signature -- only the signature data (detached mode) + cleartext -- data and signature as text (cleartext mode) + (or None if sink is given) + result -- additional information about the signature(s) + + Raises: + InvalidSigners -- if signing using a particular key failed + GPGMEError -- as signaled by the underlying library + + """ + signeddata = sink if sink else Data() + + try: + self.op_sign(data, signeddata, mode) + except errors.GPGMEError as e: + if e.getcode() == errors.UNUSABLE_SECKEY: + result = self.op_sign_result() + if result.invalid_signers: + raise errors.InvalidSigners(result.invalid_signers) + raise + + result = self.op_sign_result() + assert not result.invalid_signers + + signedbytes = None + if not sink: + signeddata.seek(0, os.SEEK_SET) + signedbytes = signeddata.read() + return signedbytes, result + + def verify(self, signed_data, signature=None, sink=None, verify=[]): + """Verify signatures + + Verify signatures over data. If VERIFY is an iterable of + keys, the ciphertext must be signed by all those keys, + otherwise an error is raised. + + Keyword arguments: + signature -- detached signature data + sink -- write result to sink instead of returning it + + Returns: + data -- the plain data + (or None if sink is given, or we verified a detached signature) + result -- additional information about the signature(s) + + Raises: + BadSignatures -- if a bad signature is encountered + MissingSignatures -- if expected signatures are missing or bad + GPGMEError -- as signaled by the underlying library + + """ + if signature: + # Detached signature, we don't return the plain text. + data = None + else: + data = sink if sink else Data() + + if signature: + self.op_verify(signature, signed_data, None) + else: + self.op_verify(signed_data, None, data) + + result = self.op_verify_result() + if any(s.status != errors.NO_ERROR for s in result.signatures): + raise errors.BadSignatures(result) + + missing = list() + for key in verify: + ok = False + for subkey in key.subkeys: + for sig in result.signatures: + if sig.summary & constants.SIGSUM_VALID == 0: + continue + if subkey.can_sign and subkey.fpr == sig.fpr: + ok = True + break + if ok: + break + if not ok: + missing.append(key) + if missing: + raise errors.MissingSignatures(result, missing) + + plainbytes = None + if data and not sink: + data.seek(0, os.SEEK_SET) + plainbytes = data.read() + return plainbytes, result + + def keylist(self, pattern=None, secret=False): + """List keys + + Keyword arguments: + pattern -- return keys matching pattern (default: all keys) + secret -- return only secret keys + + Returns: + -- an iterator returning key objects + + Raises: + GPGMEError -- as signaled by the underlying library + """ + return self.op_keylist_all(pattern, secret) + + def assuan_transact(self, command, + data_cb=None, inquire_cb=None, status_cb=None): + """Issue a raw assuan command + + This function can be used to issue a raw assuan command to the + engine. + + If command is a string or bytes, it will be used as-is. If it + is an iterable of strings, it will be properly escaped and + joined into an well-formed assuan command. + + Keyword arguments: + data_cb -- a callback receiving data lines + inquire_cb -- a callback providing more information + status_cb -- a callback receiving status lines + + Returns: + result -- the result of command as GPGMEError + + Raises: + GPGMEError -- as signaled by the underlying library + + """ + + if isinstance(command, (str, bytes)): + cmd = command + else: + cmd = " ".join(util.percent_escape(f) for f in command) + + errptr = gpgme.new_gpgme_error_t_p() + + err = gpgme.gpgme_op_assuan_transact_ext( + self.wrapped, + cmd, + (weakref.ref(self), data_cb) if data_cb else None, + (weakref.ref(self), inquire_cb) if inquire_cb else None, + (weakref.ref(self), status_cb) if status_cb else None, + errptr) + + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + + errorcheck(err) + + status = gpgme.gpgme_error_t_p_value(errptr) + gpgme.delete_gpgme_error_t_p(errptr) + + return GPGMEError(status) if status != 0 else None + + def interact(self, key, func, sink=None, flags=0, fnc_value=None): + """Interact with the engine + + This method can be used to edit keys and cards interactively. + KEY is the key to edit, FUNC is called repeatedly with two + unicode arguments, 'keyword' and 'args'. See the GPGME manual + for details. + + Keyword arguments: + sink -- if given, additional output is written here + flags -- use constants.INTERACT_CARD to edit a card + + Raises: + GPGMEError -- as signaled by the underlying library + + """ + if key == None: + raise ValueError("First argument cannot be None") + + if sink == None: + sink = Data() + + if fnc_value: + opaquedata = (weakref.ref(self), func, fnc_value) + else: + opaquedata = (weakref.ref(self), func) + + result = gpgme.gpgme_op_interact(self.wrapped, key, flags, + opaquedata, sink) + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + errorcheck(result) + + @property + def signers(self): + """Keys used for signing""" + return [self.signers_enum(i) for i in range(self.signers_count())] + @signers.setter + def signers(self, signers): + old = self.signers + self.signers_clear() + try: + for key in signers: + self.signers_add(key) + except: + self.signers = old + raise + + @property + def pinentry_mode(self): + """Pinentry mode""" + return self.get_pinentry_mode() + @pinentry_mode.setter + def pinentry_mode(self, value): + self.set_pinentry_mode(value) + + @property + def protocol(self): + """Protocol to use""" + return self.get_protocol() + @protocol.setter + def protocol(self, value): + errorcheck(gpgme.gpgme_engine_check_version(value)) + self.set_protocol(value) + + _ctype = 'gpgme_ctx_t' + _cprefix = 'gpgme_' + + def _errorcheck(self, name): + """This function should list all functions returning gpgme_error_t""" + return ((name.startswith('gpgme_op_') + and not name.endswith('_result')) + or name in { + 'gpgme_set_ctx_flag', + 'gpgme_set_protocol', + 'gpgme_set_sub_protocol', + 'gpgme_set_keylist_mode', + 'gpgme_set_pinentry_mode', + 'gpgme_set_locale', + 'gpgme_set_engine_info', + 'gpgme_signers_add', + 'gpgme_get_sig_key', + 'gpgme_sig_notation_add', + 'gpgme_cancel', + 'gpgme_cancel_async', + 'gpgme_cancel_get_key', + }) + + _boolean_properties = {'armor', 'textmode', 'offline'} + + def __del__(self): + if not gpgme: + # At interpreter shutdown, gpgme is set to NONE. + return + + self._free_passcb() + self._free_progresscb() + self._free_statuscb() + if self.own and self.wrapped and gpgme.gpgme_release: + gpgme.gpgme_release(self.wrapped) + self.wrapped = None + + # Implement the context manager protocol. + def __enter__(self): + return self + def __exit__(self, type, value, tb): + self.__del__() + + def op_keylist_all(self, *args, **kwargs): + self.op_keylist_start(*args, **kwargs) + key = self.op_keylist_next() + while key: + yield key + key = self.op_keylist_next() + self.op_keylist_end() + + def op_keylist_next(self): + """Returns the next key in the list created + by a call to op_keylist_start(). The object returned + is of type Key.""" + ptr = gpgme.new_gpgme_key_t_p() + try: + errorcheck(gpgme.gpgme_op_keylist_next(self.wrapped, ptr)) + key = gpgme.gpgme_key_t_p_value(ptr) + except errors.GPGMEError as excp: + key = None + if excp.getcode() != errors.EOF: + raise excp + gpgme.delete_gpgme_key_t_p(ptr) + if key: + key.__del__ = lambda self: gpgme.gpgme_key_unref(self) + return key + + def get_key(self, fpr, secret=False): + """Get a key given a fingerprint + + Keyword arguments: + secret -- to request a secret key + + Returns: + -- the matching key + + Raises: + KeyError -- if the key was not found + GPGMEError -- as signaled by the underlying library + + """ + ptr = gpgme.new_gpgme_key_t_p() + + try: + errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret)) + except errors.GPGMEError as e: + if e.getcode() == errors.EOF: + raise errors.KeyNotFound(fpr) + raise e + + key = gpgme.gpgme_key_t_p_value(ptr) + gpgme.delete_gpgme_key_t_p(ptr) + assert key + key.__del__ = lambda self: gpgme.gpgme_key_unref(self) + return key + + def op_trustlist_all(self, *args, **kwargs): + self.op_trustlist_start(*args, **kwargs) + trust = self.op_trustlist_next() + while trust: + yield trust + trust = self.op_trustlist_next() + self.op_trustlist_end() + + def op_trustlist_next(self): + """Returns the next trust item in the list created + by a call to op_trustlist_start(). The object returned + is of type TrustItem.""" + ptr = gpgme.new_gpgme_trust_item_t_p() + try: + errorcheck(gpgme.gpgme_op_trustlist_next(self.wrapped, ptr)) + trust = gpgme.gpgme_trust_item_t_p_value(ptr) + except errors.GPGMEError as excp: + trust = None + if excp.getcode() != errors.EOF: + raise + gpgme.delete_gpgme_trust_item_t_p(ptr) + return trust + + def set_passphrase_cb(self, func, hook=None): + """Sets the passphrase callback to the function specified by func. + + When the system needs a passphrase, it will call func with three args: + hint, a string describing the key it needs the passphrase for; + desc, a string describing the passphrase it needs; + prev_bad, a boolean equal True if this is a call made after + unsuccessful previous attempt. + + If hook has a value other than None it will be passed into the func + as a forth argument. + + Please see the GPGME manual for more information. + """ + if func == None: + hookdata = None + else: + if hook == None: + hookdata = (weakref.ref(self), func) + else: + hookdata = (weakref.ref(self), func, hook) + gpgme.gpg_set_passphrase_cb(self, hookdata) + + def _free_passcb(self): + if gpgme.gpg_set_passphrase_cb: + self.set_passphrase_cb(None) + + def set_progress_cb(self, func, hook=None): + """Sets the progress meter callback to the function specified by FUNC. + If FUNC is None, the callback will be cleared. + + This function will be called to provide an interactive update + of the system's progress. The function will be called with + three arguments, type, total, and current. If HOOK is not + None, it will be supplied as fourth argument. + + Please see the GPGME manual for more information. + + """ + if func == None: + hookdata = None + else: + if hook == None: + hookdata = (weakref.ref(self), func) + else: + hookdata = (weakref.ref(self), func, hook) + gpgme.gpg_set_progress_cb(self, hookdata) + + def _free_progresscb(self): + if gpgme.gpg_set_progress_cb: + self.set_progress_cb(None) + + def set_status_cb(self, func, hook=None): + """Sets the status callback to the function specified by FUNC. If + FUNC is None, the callback will be cleared. + + The function will be called with two arguments, keyword and + args. If HOOK is not None, it will be supplied as third + argument. + + Please see the GPGME manual for more information. + + """ + if func == None: + hookdata = None + else: + if hook == None: + hookdata = (weakref.ref(self), func) + else: + hookdata = (weakref.ref(self), func, hook) + gpgme.gpg_set_status_cb(self, hookdata) + + def _free_statuscb(self): + if gpgme.gpg_set_status_cb: + self.set_status_cb(None) + + @property + def engine_info(self): + """Configuration of the engine currently in use""" + p = self.protocol + infos = [i for i in self.get_engine_info() if i.protocol == p] + assert len(infos) == 1 + return infos[0] + + def get_engine_info(self): + """Get engine configuration + + Returns information about all configured and installed + engines. + + Returns: + infos -- a list of engine infos + + """ + return gpgme.gpgme_ctx_get_engine_info(self.wrapped) + + def set_engine_info(self, proto, file_name=None, home_dir=None): + """Change engine configuration + + Changes the configuration of the crypto engine implementing + the protocol 'proto' for the context. + + Keyword arguments: + file_name -- engine program file name (unchanged if None) + home_dir -- configuration directory (unchanged if None) + + """ + errorcheck(gpgme.gpgme_ctx_set_engine_info( + self.wrapped, proto, file_name, home_dir)) + + def wait(self, hang): + """Wait for asynchronous call to finish. Wait forever if hang is True. + Raises an exception on errors. + + Please read the GPGME manual for more information. + + """ + ptr = gpgme.new_gpgme_error_t_p() + gpgme.gpgme_wait(self.wrapped, ptr, hang) + status = gpgme.gpgme_error_t_p_value(ptr) + gpgme.delete_gpgme_error_t_p(ptr) + errorcheck(status) + + def op_edit(self, key, func, fnc_value, out): + """Start key editing using supplied callback function + + Note: This interface is deprecated and will be removed with + GPGME 1.8. Please use .interact instead. Furthermore, we + implement this using gpgme_op_interact, so callbacks will get + called with string keywords instead of numeric status + messages. Code that is using constants.STATUS_X or + constants.status.X will continue to work, whereas code using + magic numbers will break as a result. + + """ + warnings.warn("Call to deprecated method op_edit.", + category=DeprecationWarning) + return self.interact(key, func, sink=out, fnc_value=fnc_value) + + +class Data(GpgmeWrapper): + """Data buffer + + A lot of data has to be exchanged between the user and the crypto + engine, like plaintext messages, ciphertext, signatures and + information about the keys. The technical details about + exchanging the data information are completely abstracted by + GPGME. The user provides and receives the data via `gpgme_data_t' + objects, regardless of the communication protocol between GPGME + and the crypto engine in use. + + This Data class is the implementation of the GpgmeData objects. + + Please see the information about __init__ for instantiation. + + """ + + _ctype = 'gpgme_data_t' + _cprefix = 'gpgme_data_' + + def _errorcheck(self, name): + """This function should list all functions returning gpgme_error_t""" + return name not in { + 'gpgme_data_release_and_get_mem', + 'gpgme_data_get_encoding', + 'gpgme_data_seek', + 'gpgme_data_get_file_name', + } + + def __init__(self, string=None, file=None, offset=None, + length=None, cbs=None, copy=True): + """Initialize a new gpgme_data_t object. + + If no args are specified, make it an empty object. + + If string alone is specified, initialize it with the data + contained there. + + If file, offset, and length are all specified, file must + be either a filename or a file-like object, and the object + will be initialized by reading the specified chunk from the file. + + If cbs is specified, it MUST be a tuple of the form: + + (read_cb, write_cb, seek_cb, release_cb[, hook]) + + where the first four items are functions implementing reading, + writing, seeking the data, and releasing any resources once + the data object is deallocated. The functions must match the + following prototypes: + + def read(amount, hook=None): + return + + def write(data, hook=None): + return + + def seek(offset, whence, hook=None): + return + + def release(hook=None): + + + The functions may be bound methods. In that case, you can + simply use the 'self' reference instead of using a hook. + + If file is specified without any other arguments, then + it must be a filename, and the object will be initialized from + that file. + + """ + super(Data, self).__init__(None) + self.data_cbs = None + + if cbs != None: + self.new_from_cbs(*cbs) + elif string != None: + self.new_from_mem(string, copy) + elif file != None and offset != None and length != None: + self.new_from_filepart(file, offset, length) + elif file != None: + if util.is_a_string(file): + self.new_from_file(file, copy) + else: + self.new_from_fd(file) + else: + self.new() + + def __del__(self): + if not gpgme: + # At interpreter shutdown, gpgme is set to NONE. + return + + if self.wrapped != None and gpgme.gpgme_data_release: + gpgme.gpgme_data_release(self.wrapped) + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + self.wrapped = None + self._free_datacbs() + + # Implement the context manager protocol. + def __enter__(self): + return self + def __exit__(self, type, value, tb): + self.__del__() + + def _free_datacbs(self): + self._data_cbs = None + + def new(self): + tmp = gpgme.new_gpgme_data_t_p() + errorcheck(gpgme.gpgme_data_new(tmp)) + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_mem(self, string, copy=True): + tmp = gpgme.new_gpgme_data_t_p() + errorcheck(gpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy)) + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_file(self, filename, copy=True): + tmp = gpgme.new_gpgme_data_t_p() + try: + errorcheck(gpgme.gpgme_data_new_from_file(tmp, filename, copy)) + except errors.GPGMEError as e: + if e.getcode() == errors.INV_VALUE and not copy: + raise ValueError("delayed reads are not yet supported") + else: + raise e + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None): + tmp = gpgme.new_gpgme_data_t_p() + if hook != None: + hookdata = (weakref.ref(self), + read_cb, write_cb, seek_cb, release_cb, hook) + else: + hookdata = (weakref.ref(self), + read_cb, write_cb, seek_cb, release_cb) + gpgme.gpg_data_new_from_cbs(self, hookdata, tmp) + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_filepart(self, file, offset, length): + """This wraps the GPGME gpgme_data_new_from_filepart() function. + The argument "file" may be: + + * a string specifying a file name, or + * a file-like object supporting the fileno() and the mode attribute. + + """ + + tmp = gpgme.new_gpgme_data_t_p() + filename = None + fp = None + + if util.is_a_string(file): + filename = file + else: + fp = gpgme.fdopen(file.fileno(), file.mode) + if fp == None: + raise ValueError("Failed to open file from %s arg %s" % \ + (str(type(file)), str(file))) + + errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp, + offset, length)) + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_fd(self, file): + """This wraps the GPGME gpgme_data_new_from_fd() function. The + argument "file" must be a file-like object, supporting the + fileno() method. + + """ + tmp = gpgme.new_gpgme_data_t_p() + errorcheck(gpgme.gpgme_data_new_from_fd(tmp, file.fileno())) + self.wrapped = gpgme.gpgme_data_t_p_value(tmp) + gpgme.delete_gpgme_data_t_p(tmp) + + def new_from_stream(self, file): + """This wrap around gpgme_data_new_from_stream is an alias for + new_from_fd() method since in python there's not difference + between file stream and file descriptor""" + self.new_from_fd(file) + + def write(self, buffer): + """Write buffer given as string or bytes. + + If a string is given, it is implicitly encoded using UTF-8.""" + written = gpgme.gpgme_data_write(self.wrapped, buffer) + if written < 0: + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + else: + raise GPGMEError.fromSyserror() + return written + + def read(self, size = -1): + """Read at most size bytes, returned as bytes. + + If the size argument is negative or omitted, read until EOF is reached. + + Returns the data read, or the empty string if there was no data + to read before EOF was reached.""" + + if size == 0: + return '' + + if size > 0: + try: + result = gpgme.gpgme_data_read(self.wrapped, size) + except: + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + else: + raise + return result + else: + chunks = [] + while True: + try: + result = gpgme.gpgme_data_read(self.wrapped, 4096) + except: + if self._callback_excinfo: + gpgme.gpg_raise_callback_exception(self) + else: + raise + if len(result) == 0: + break + chunks.append(result) + return b''.join(chunks) + +def pubkey_algo_name(algo): + return gpgme.gpgme_pubkey_algo_name(algo) + +def hash_algo_name(algo): + return gpgme.gpgme_hash_algo_name(algo) + +def get_protocol_name(proto): + return gpgme.gpgme_get_protocol_name(proto) + +def check_version(version=None): + return gpgme.gpgme_check_version(version) + +# check_version also makes sure that several subsystems are properly +# initialized, and it must be run at least once before invoking any +# other function. We do it here so that the user does not have to do +# it unless she really wants to check for a certain version. +check_version() + +def engine_check_version (proto): + try: + errorcheck(gpgme.gpgme_engine_check_version(proto)) + return True + except errors.GPGMEError: + return False + +def get_engine_info(): + ptr = gpgme.new_gpgme_engine_info_t_p() + try: + errorcheck(gpgme.gpgme_get_engine_info(ptr)) + info = gpgme.gpgme_engine_info_t_p_value(ptr) + except errors.GPGMEError: + info = None + gpgme.delete_gpgme_engine_info_t_p(ptr) + return info + +def set_engine_info(proto, file_name, home_dir=None): + """Changes the default configuration of the crypto engine implementing + the protocol 'proto'. 'file_name' is the file name of + the executable program implementing this protocol. 'home_dir' is the + directory name of the configuration directory (engine's default is + used if omitted).""" + errorcheck(gpgme.gpgme_set_engine_info(proto, file_name, home_dir)) + +def set_locale(category, value): + """Sets the default locale used by contexts""" + errorcheck(gpgme.gpgme_set_locale(None, category, value)) + +def wait(hang): + """Wait for asynchronous call on any Context to finish. + Wait forever if hang is True. + + For finished anynch calls it returns a tuple (status, context): + status - status return by asnynchronous call. + context - context which caused this call to return. + + Please read the GPGME manual of more information.""" + ptr = gpgme.new_gpgme_error_t_p() + context = gpgme.gpgme_wait(None, ptr, hang) + status = gpgme.gpgme_error_t_p_value(ptr) + gpgme.delete_gpgme_error_t_p(ptr) + if context == None: + errorcheck(status) + else: + context = Context(context) + return (status, context) diff --git a/lang/python/gpg/errors.py b/lang/python/gpg/errors.py new file mode 100644 index 00000000..7f037f0a --- /dev/null +++ b/lang/python/gpg/errors.py @@ -0,0 +1,127 @@ +# Copyright (C) 2004 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +from . import gpgme +from . import util + +# To appease static analysis tools, we define some constants here. +# They are overwritten with the proper values by process_constants. +NO_ERROR = None +EOF = None + +util.process_constants('GPG_ERR_', globals()) + +class GpgError(Exception): + pass + +class GPGMEError(GpgError): + def __init__(self, error = None, message = None): + self.error = error + self.message = message + + @classmethod + def fromSyserror(cls): + return cls(gpgme.gpgme_err_code_from_syserror()) + + def getstring(self): + message = "%s: %s" % (gpgme.gpgme_strsource(self.error), + gpgme.gpgme_strerror(self.error)) + if self.message != None: + message = "%s: %s" % (self.message, message) + return message + + def getcode(self): + return gpgme.gpgme_err_code(self.error) + + def getsource(self): + return gpgme.gpgme_err_source(self.error) + + def __str__(self): + return self.getstring() + +def errorcheck(retval, extradata = None): + if retval: + raise GPGMEError(retval, extradata) + +class KeyNotFound(GPGMEError, KeyError): + """Raised if a key was not found + + GPGME indicates this condition with EOF, which is not very + idiomatic. We raise this error that is both a GPGMEError + indicating EOF, and a KeyError. + + """ + def __init__(self, keystr): + self.keystr = keystr + GPGMEError.__init__(self, EOF) + def __str__(self): + return self.keystr + +# These errors are raised in the idiomatic interface code. + +class EncryptionError(GpgError): + pass + +class InvalidRecipients(EncryptionError): + def __init__(self, recipients): + self.recipients = recipients + def __str__(self): + return ", ".join("{}: {}".format(r.fpr, + gpgme.gpgme_strerror(r.reason)) + for r in self.recipients) + +class DeryptionError(GpgError): + pass + +class UnsupportedAlgorithm(DeryptionError): + def __init__(self, algorithm): + self.algorithm = algorithm + def __str__(self): + return self.algorithm + +class SigningError(GpgError): + pass + +class InvalidSigners(SigningError): + def __init__(self, signers): + self.signers = signers + def __str__(self): + return ", ".join("{}: {}".format(s.fpr, + gpgme.gpgme_strerror(s.reason)) + for s in self.signers) + +class VerificationError(GpgError): + pass + +class BadSignatures(VerificationError): + def __init__(self, result): + self.result = result + def __str__(self): + return ", ".join("{}: {}".format(s.fpr, + gpgme.gpgme_strerror(s.status)) + for s in self.result.signatures + if s.status != NO_ERROR) + +class MissingSignatures(VerificationError): + def __init__(self, result, missing): + self.result = result + self.missing = missing + def __str__(self): + return ", ".join(k.subkeys[0].fpr for k in self.missing) diff --git a/lang/python/gpg/results.py b/lang/python/gpg/results.py new file mode 100644 index 00000000..3383896b --- /dev/null +++ b/lang/python/gpg/results.py @@ -0,0 +1,118 @@ +# Robust result objects +# +# 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 Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 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 + +"""Robust result objects + +Results returned by the underlying library are fragile, i.e. they are +only valid until the next operation is performed in the context. + +We cannot arbitrarily constrain the lifetime of Python objects, we +therefore create deep copies of the results. + +""" + +class Result(object): + """Result object + + Describes the result of an operation. + + """ + + """Convert to types""" + _type = {} + + """Map functions over list attributes""" + _map = {} + + """Automatically copy unless blacklisted""" + _blacklist = { + 'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown', + } + def __init__(self, fragile): + for key, func in self._type.items(): + if hasattr(fragile, key): + setattr(self, key, func(getattr(fragile, key))) + + for key, func in self._map.items(): + if hasattr(fragile, key): + setattr(self, key, list(map(func, getattr(fragile, key)))) + + for key in dir(fragile): + if key.startswith('_') or key in self._blacklist: + continue + if hasattr(self, key): + continue + + setattr(self, key, getattr(fragile, key)) + + def __str__(self): + return '<{} {}>'.format( + self.__class__.__name__, + ', '.join('{}: {}'.format(k, getattr(self, k)) + for k in dir(self) if not k.startswith('_'))) + +class InvalidKey(Result): + pass + +class EncryptResult(Result): + _map = dict(invalid_recipients=InvalidKey) + +class Recipient(Result): + pass + +class DecryptResult(Result): + _type = dict(wrong_key_usage=bool) + _map = dict(recipients=Recipient) + +class NewSignature(Result): + pass + +class SignResult(Result): + _map = dict(invalid_signers=InvalidKey, signatures=NewSignature) + +class Notation(Result): + pass + +class Signature(Result): + _type = dict(wrong_key_usage=bool, chain_model=bool) + _map = dict(notations=Notation) + +class VerifyResult(Result): + _map = dict(signatures=Signature) + +class ImportStatus(Result): + pass + +class ImportResult(Result): + _map = dict(imports=ImportStatus) + +class GenkeyResult(Result): + _type = dict(primary=bool, sub=bool) + +class KeylistResult(Result): + _type = dict(truncated=bool) + +class VFSMountResult(Result): + pass + +class EngineInfo(Result): + pass diff --git a/lang/python/gpg/util.py b/lang/python/gpg/util.py new file mode 100644 index 00000000..e4fca4c1 --- /dev/null +++ b/lang/python/gpg/util.py @@ -0,0 +1,53 @@ +# Copyright (C) 2016 g10 Code GmbH +# Copyright (C) 2004,2008 Igor Belyi +# Copyright (C) 2002 John Goerzen +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function, unicode_literals +del absolute_import, print_function, unicode_literals + +import sys + +def process_constants(prefix, scope): + """Called by the constant modules to load up the constants from the C + library starting with PREFIX. Matching constants will be inserted + into SCOPE with PREFIX stripped from the names. Returns the names + of inserted constants. + + """ + from . import gpgme + index = len(prefix) + constants = {identifier[index:]: getattr(gpgme, identifier) + for identifier in dir(gpgme) + if identifier.startswith(prefix)} + scope.update(constants) + return list(constants.keys()) + +def percent_escape(s): + return ''.join( + '%{0:2x}'.format(ord(c)) + if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c + for c in s) + +# Python2/3 compatibility +if sys.version_info[0] == 3: + # Python3 + def is_a_string(x): + return isinstance(x, str) +else: + # Python2 + def is_a_string(x): + return isinstance(x, basestring) diff --git a/lang/python/gpg/version.py.in b/lang/python/gpg/version.py.in new file mode 100644 index 00000000..1a1baf08 --- /dev/null +++ b/lang/python/gpg/version.py.in @@ -0,0 +1,68 @@ +# Copyright (C) 2016 g10 Code GmbH +# Copyright (C) 2015 Ben McGinnes +# Copyright (C) 2004 Igor Belyi +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import, print_function +del absolute_import, print_function + +from . import gpgme + +productname = 'gpg' +versionstr = "@VERSION@" +gpgme_versionstr = gpgme.GPGME_VERSION +in_tree_build = bool(gpgme.cvar.gpg_in_tree_build) + +versionlist = versionstr.split(".") +major = versionlist[0] +minor = versionlist[1] +patch = versionlist[2] + +copyright = """\ +Copyright (C) 2016 g10 Code GmbH +Copyright (C) 2015 Ben McGinnes +Copyright (C) 2014-2015 Martin Albrecht +Copyright (C) 2004-2008 Igor Belyi +Copyright (C) 2002 John Goerzen""" + +author = "The GnuPG hackers" +author_email = "gnupg-devel@gnupg.org" + +description = "Python support for GPGME GnuPG cryptography library" +homepage = "https://gnupg.org" + +license = """Copyright (C) 2016 g10 Code GmbH +Copyright (C) 2015 Ben McGinnes +Copyright (C) 2014, 2015 Martin Albrecht +Copyright (C) 2004, 2008 Igor Belyi +Copyright (C) 2002 John Goerzen + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA""" + +# Interface hygiene. Keep this at the end. +del gpgme diff --git a/lang/python/gpgme.i b/lang/python/gpgme.i index 5d074aa9..783531f7 100644 --- a/lang/python/gpgme.i +++ b/lang/python/gpgme.i @@ -159,7 +159,7 @@ $1 = NULL; else { PyObject *pypointer; - pypointer = _pyme_obj2gpgme_data_t($input, $argnum, &wrapper, + pypointer = _gpg_obj2gpgme_data_t($input, $argnum, &wrapper, &bytesio, &view); if (pypointer == NULL) return NULL; @@ -428,7 +428,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "EncryptResult"); + $result = _gpg_wrap_result(fragile, "EncryptResult"); Py_DECREF(fragile); } @@ -436,7 +436,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "DecryptResult"); + $result = _gpg_wrap_result(fragile, "DecryptResult"); Py_DECREF(fragile); } @@ -444,7 +444,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "SignResult"); + $result = _gpg_wrap_result(fragile, "SignResult"); Py_DECREF(fragile); } @@ -452,7 +452,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "VerifyResult"); + $result = _gpg_wrap_result(fragile, "VerifyResult"); Py_DECREF(fragile); } @@ -460,7 +460,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "ImportResult"); + $result = _gpg_wrap_result(fragile, "ImportResult"); Py_DECREF(fragile); } @@ -468,7 +468,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "GenkeyResult"); + $result = _gpg_wrap_result(fragile, "GenkeyResult"); Py_DECREF(fragile); } @@ -476,7 +476,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "KeylistResult"); + $result = _gpg_wrap_result(fragile, "KeylistResult"); Py_DECREF(fragile); } @@ -484,7 +484,7 @@ PyObject *fragile; fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, %newpointer_flags); - $result = _pyme_wrap_result(fragile, "VFSMountResult"); + $result = _gpg_wrap_result(fragile, "VFSMountResult"); Py_DECREF(fragile); } @@ -507,7 +507,7 @@ Py_DECREF($result); return NULL; /* raise */ } - o = _pyme_wrap_result(fragile, "EngineInfo"); + o = _gpg_wrap_result(fragile, "EngineInfo"); Py_DECREF(fragile); if (o == NULL) { @@ -528,7 +528,7 @@ return PyErr_Format(PyExc_TypeError, "interact callback must be a tuple of size 2 or 3"); - $1 = (gpgme_interact_cb_t) _pyme_interact_cb; + $1 = (gpgme_interact_cb_t) _gpg_interact_cb; $2 = $input; } @@ -547,7 +547,7 @@ "callback must be a tuple of size 2"); if (! PyCallable_Check(PyTuple_GetItem($input, 1))) return PyErr_Format(PyExc_TypeError, "second item must be callable"); - $1 = _pyme_assuan_data_cb; + $1 = _gpg_assuan_data_cb; $2 = $input; } } @@ -564,7 +564,7 @@ "callback must be a tuple of size 2"); if (! PyCallable_Check(PyTuple_GetItem($input, 1))) return PyErr_Format(PyExc_TypeError, "second item must be callable"); - $1 = _pyme_assuan_inquire_cb; + $1 = _gpg_assuan_inquire_cb; $2 = $input; } } @@ -581,7 +581,7 @@ "callback must be a tuple of size 2"); if (! PyCallable_Check(PyTuple_GetItem($input, 1))) return PyErr_Format(PyExc_TypeError, "second item must be callable"); - $1 = _pyme_assuan_status_cb; + $1 = _gpg_assuan_status_cb; $2 = $input; } } @@ -654,13 +654,13 @@ FILE *fdopen(int fildes, const char *mode); /* SWIG runtime support for helpers.c */ PyObject * -_pyme_wrap_gpgme_data_t(gpgme_data_t data) +_gpg_wrap_gpgme_data_t(gpgme_data_t data) { return SWIG_Python_NewPointerObj(NULL, data, SWIGTYPE_p_gpgme_data, 0); } gpgme_ctx_t -_pyme_unwrap_gpgme_ctx_t(PyObject *wrapped) +_gpg_unwrap_gpgme_ctx_t(PyObject *wrapped) { gpgme_ctx_t result; if (SWIG_ConvertPtr(wrapped, diff --git a/lang/python/helpers.c b/lang/python/helpers.c index 3724752f..8f71a305 100644 --- a/lang/python/helpers.c +++ b/lang/python/helpers.c @@ -33,7 +33,7 @@ #include "private.h" /* Flag specifying whether this is an in-tree build. */ -int pyme_in_tree_build = +int gpg_in_tree_build = #if IN_TREE_BUILD 1 #else @@ -43,7 +43,7 @@ int pyme_in_tree_build = static PyObject *GPGMEError = NULL; -void _pyme_exception_init(void) { +void _gpg_exception_init(void) { if (GPGMEError == NULL) { PyObject *errors; PyObject *from_list = PyList_New(0); @@ -58,11 +58,11 @@ void _pyme_exception_init(void) { } static PyObject * -_pyme_raise_exception(gpgme_error_t err) +_gpg_raise_exception(gpgme_error_t err) { PyObject *e; - _pyme_exception_init(); + _gpg_exception_init(); if (GPGMEError == NULL) return PyErr_Format(PyExc_RuntimeError, "Got gpgme_error_t %d", err); @@ -76,7 +76,7 @@ _pyme_raise_exception(gpgme_error_t err) return NULL; /* raise */ } -gpgme_error_t _pyme_exception2code(void) { +gpgme_error_t _gpg_exception2code(void) { gpgme_error_t err_status = gpg_error(GPG_ERR_GENERAL); if (GPGMEError && PyErr_ExceptionMatches(GPGMEError)) { PyObject *type = 0, *value = 0, *traceback = 0; @@ -94,7 +94,7 @@ gpgme_error_t _pyme_exception2code(void) { /* Exception support for callbacks. */ #define EXCINFO "_callback_excinfo" -static void _pyme_stash_callback_exception(PyObject *weak_self) +static void _gpg_stash_callback_exception(PyObject *weak_self) { PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo; @@ -136,7 +136,7 @@ static void _pyme_stash_callback_exception(PyObject *weak_self) Py_DECREF(excinfo); } -PyObject *pyme_raise_callback_exception(PyObject *self) +PyObject *gpg_raise_callback_exception(PyObject *self) { PyGILState_STATE state = PyGILState_Ensure(); PyObject *ptype, *pvalue, *ptraceback, *excinfo; @@ -192,7 +192,7 @@ PyObject *pyme_raise_callback_exception(PyObject *self) /* Convert object to a pointer to gpgme type, generic version. */ PyObject * -_pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum) +_gpg_obj2gpgme_t(PyObject *input, const char *objtype, int argnum) { PyObject *pyname = NULL, *pypointer = NULL; pyname = PyObject_GetAttrString(input, "_ctype"); @@ -229,7 +229,7 @@ _pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum) objects with a fileno method, returning it in WRAPPER. This object must be de-referenced when no longer needed. */ PyObject * -_pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, +_gpg_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, PyObject **bytesio, Py_buffer *view) { gpgme_error_t err; @@ -242,9 +242,9 @@ _pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, err = gpgme_data_new_from_fd(wrapper, (int) PyLong_AsLong(fd)); Py_DECREF(fd); if (err) - return _pyme_raise_exception (err); + return _gpg_raise_exception (err); - return _pyme_wrap_gpgme_data_t(*wrapper); + return _gpg_wrap_gpgme_data_t(*wrapper); } else PyErr_Clear(); @@ -283,17 +283,17 @@ _pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, err = gpgme_data_new_from_mem(wrapper, view->buf, (size_t) view->len, 0); if (err) - return _pyme_raise_exception (err); + return _gpg_raise_exception (err); - return _pyme_wrap_gpgme_data_t(*wrapper); + return _gpg_wrap_gpgme_data_t(*wrapper); } /* As last resort we assume it is a wrapped data object. */ if (PyObject_HasAttrString(data, "_ctype")) - return _pyme_obj2gpgme_t(data, "gpgme_data_t", argnum); + return _gpg_obj2gpgme_t(data, "gpgme_data_t", argnum); return PyErr_Format(PyExc_TypeError, - "arg %d: expected pyme.Data, file, or an object " + "arg %d: expected gpg.Data, file, or an object " "implementing the buffer protocol, got %s", argnum, data->ob_type->tp_name); } @@ -301,7 +301,7 @@ _pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, PyObject * -_pyme_wrap_result(PyObject *fragile, const char *classname) +_gpg_wrap_result(PyObject *fragile, const char *classname) { static PyObject *results; PyObject *class; @@ -348,7 +348,7 @@ static gpgme_error_t pyPassphraseCb(void *hook, PyObject *encoded = NULL; gpgme_error_t err_status = 0; - _pyme_exception_init(); + _gpg_exception_init(); assert (PyTuple_Check(pyhook)); assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3); @@ -385,12 +385,12 @@ static gpgme_error_t pyPassphraseCb(void *hook, retval = PyObject_CallObject(func, args); Py_DECREF(args); if (PyErr_Occurred()) { - err_status = _pyme_exception2code(); + err_status = _gpg_exception2code(); } else { if (!retval) { if (write(fd, "\n", 1) < 0) { err_status = gpgme_error_from_syserror (); - _pyme_raise_exception (err_status); + _gpg_raise_exception (err_status); } } else { char *buf; @@ -425,11 +425,11 @@ static gpgme_error_t pyPassphraseCb(void *hook, if (write(fd, buf, len) < 0) { err_status = gpgme_error_from_syserror (); - _pyme_raise_exception (err_status); + _gpg_raise_exception (err_status); } if (! err_status && write(fd, "\n", 1) < 0) { err_status = gpgme_error_from_syserror (); - _pyme_raise_exception (err_status); + _gpg_raise_exception (err_status); } Py_DECREF(retval); @@ -438,7 +438,7 @@ static gpgme_error_t pyPassphraseCb(void *hook, leave: if (err_status) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); Py_XDECREF(encoded); PyGILState_Release(state); @@ -446,7 +446,7 @@ static gpgme_error_t pyPassphraseCb(void *hook, } PyObject * -pyme_set_passphrase_cb(PyObject *self, PyObject *cb) { +gpg_set_passphrase_cb(PyObject *self, PyObject *cb) { PyGILState_STATE state = PyGILState_Ensure(); PyObject *wrapped; gpgme_ctx_t ctx; @@ -459,7 +459,7 @@ pyme_set_passphrase_cb(PyObject *self, PyObject *cb) { return NULL; } - ctx = _pyme_unwrap_gpgme_ctx_t(wrapped); + ctx = _gpg_unwrap_gpgme_ctx_t(wrapped); Py_DECREF(wrapped); if (ctx == NULL) { @@ -512,7 +512,7 @@ static void pyProgressCb(void *hook, const char *what, int type, int current, PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(what, strlen (what), "strict")); if (PyErr_Occurred()) { - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); Py_DECREF(args); PyGILState_Release(state); return; @@ -527,14 +527,14 @@ static void pyProgressCb(void *hook, const char *what, int type, int current, retval = PyObject_CallObject(func, args); if (PyErr_Occurred()) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); Py_DECREF(args); Py_XDECREF(retval); PyGILState_Release(state); } PyObject * -pyme_set_progress_cb(PyObject *self, PyObject *cb) { +gpg_set_progress_cb(PyObject *self, PyObject *cb) { PyGILState_STATE state = PyGILState_Ensure(); PyObject *wrapped; gpgme_ctx_t ctx; @@ -547,7 +547,7 @@ pyme_set_progress_cb(PyObject *self, PyObject *cb) { return NULL; } - ctx = _pyme_unwrap_gpgme_ctx_t(wrapped); + ctx = _gpg_unwrap_gpgme_ctx_t(wrapped); Py_DECREF(wrapped); if (ctx == NULL) { @@ -624,19 +624,19 @@ static gpgme_error_t pyStatusCb(void *hook, const char *keyword, retval = PyObject_CallObject(func, pyargs); if (PyErr_Occurred()) - err = _pyme_exception2code(); + err = _gpg_exception2code(); Py_DECREF(pyargs); Py_XDECREF(retval); leave: if (err) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); PyGILState_Release(state); return err; } PyObject * -pyme_set_status_cb(PyObject *self, PyObject *cb) { +gpg_set_status_cb(PyObject *self, PyObject *cb) { PyGILState_STATE state = PyGILState_Ensure(); PyObject *wrapped; gpgme_ctx_t ctx; @@ -649,7 +649,7 @@ pyme_set_status_cb(PyObject *self, PyObject *cb) { return NULL; } - ctx = _pyme_unwrap_gpgme_ctx_t(wrapped); + ctx = _gpg_unwrap_gpgme_ctx_t(wrapped); Py_DECREF(wrapped); if (ctx == NULL) { @@ -684,7 +684,7 @@ pyme_set_status_cb(PyObject *self, PyObject *cb) { /* Interact callbacks. */ gpgme_error_t -_pyme_interact_cb(void *opaque, const char *keyword, +_gpg_interact_cb(void *opaque, const char *keyword, const char *args, int fd) { PyGILState_STATE state = PyGILState_Ensure(); @@ -694,7 +694,7 @@ _pyme_interact_cb(void *opaque, const char *keyword, gpgme_error_t err_status = 0; PyObject *self = NULL; - _pyme_exception_init(); + _gpg_exception_init(); assert (PyTuple_Check(pyopaque)); assert (PyTuple_Size(pyopaque) == 2 || PyTuple_Size(pyopaque) == 3); @@ -725,7 +725,7 @@ _pyme_interact_cb(void *opaque, const char *keyword, retval = PyObject_CallObject(func, pyargs); Py_DECREF(pyargs); if (PyErr_Occurred()) { - err_status = _pyme_exception2code(); + err_status = _gpg_exception2code(); } else { if (fd>=0 && retval && PyUnicode_Check(retval)) { PyObject *encoded = NULL; @@ -747,18 +747,18 @@ _pyme_interact_cb(void *opaque, const char *keyword, if (write(fd, buffer, size) < 0) { err_status = gpgme_error_from_syserror (); - _pyme_raise_exception (err_status); + _gpg_raise_exception (err_status); } if (! err_status && write(fd, "\n", 1) < 0) { err_status = gpgme_error_from_syserror (); - _pyme_raise_exception (err_status); + _gpg_raise_exception (err_status); } Py_DECREF(encoded); } } leave: if (err_status) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); Py_XDECREF(retval); PyGILState_Release(state); @@ -804,7 +804,7 @@ static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size) retval = PyObject_CallObject(func, pyargs); Py_DECREF(pyargs); if (PyErr_Occurred()) { - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; goto leave; } @@ -813,7 +813,7 @@ static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size) PyErr_Format(PyExc_TypeError, "expected bytes from read callback, got %s", retval->ob_type->tp_name); - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; goto leave; } @@ -822,7 +822,7 @@ static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size) PyErr_Format(PyExc_TypeError, "expected %zu bytes from read callback, got %zu", size, PyBytes_Size(retval)); - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; goto leave; } @@ -871,7 +871,7 @@ static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size) retval = PyObject_CallObject(func, pyargs); Py_DECREF(pyargs); if (PyErr_Occurred()) { - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; goto leave; } @@ -887,7 +887,7 @@ static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size) PyErr_Format(PyExc_TypeError, "expected int from write callback, got %s", retval->ob_type->tp_name); - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; } @@ -938,7 +938,7 @@ static off_t pyDataSeekCb(void *hook, off_t offset, int whence) retval = PyObject_CallObject(func, pyargs); Py_DECREF(pyargs); if (PyErr_Occurred()) { - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; goto leave; } @@ -958,7 +958,7 @@ static off_t pyDataSeekCb(void *hook, off_t offset, int whence) PyErr_Format(PyExc_TypeError, "expected int from seek callback, got %s", retval->ob_type->tp_name); - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); result = -1; } @@ -1000,12 +1000,12 @@ static void pyDataReleaseCb(void *hook) Py_XDECREF(retval); Py_DECREF(pyargs); if (PyErr_Occurred()) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); PyGILState_Release(state); } PyObject * -pyme_data_new_from_cbs(PyObject *self, +gpg_data_new_from_cbs(PyObject *self, PyObject *pycbs, gpgme_data_t *r_data) { @@ -1026,7 +1026,7 @@ pyme_data_new_from_cbs(PyObject *self, err = gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs); if (err) - return _pyme_raise_exception(err); + return _gpg_raise_exception(err); PyObject_SetAttrString(self, "_data_cbs", pycbs); @@ -1040,7 +1040,7 @@ pyme_data_new_from_cbs(PyObject *self, /* The assuan callbacks. */ gpgme_error_t -_pyme_assuan_data_cb (void *hook, const void *data, size_t datalen) +_gpg_assuan_data_cb (void *hook, const void *data, size_t datalen) { PyGILState_STATE state = PyGILState_Ensure(); gpgme_error_t err = 0; @@ -1059,25 +1059,25 @@ _pyme_assuan_data_cb (void *hook, const void *data, size_t datalen) py_data = PyBytes_FromStringAndSize(data, datalen); if (py_data == NULL) { - err = _pyme_exception2code(); + err = _gpg_exception2code(); goto leave; } retval = PyObject_CallFunctionObjArgs(func, py_data, NULL); if (PyErr_Occurred()) - err = _pyme_exception2code(); + err = _gpg_exception2code(); Py_DECREF(py_data); Py_XDECREF(retval); leave: if (err) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); PyGILState_Release(state); return err; } gpgme_error_t -_pyme_assuan_inquire_cb (void *hook, const char *name, const char *args, +_gpg_assuan_inquire_cb (void *hook, const char *name, const char *args, gpgme_data_t *r_data) { PyGILState_STATE state = PyGILState_Ensure(); @@ -1098,20 +1098,20 @@ _pyme_assuan_inquire_cb (void *hook, const char *name, const char *args, py_name = PyUnicode_FromString(name); if (py_name == NULL) { - err = _pyme_exception2code(); + err = _gpg_exception2code(); goto leave; } py_args = PyUnicode_FromString(args); if (py_args == NULL) { - err = _pyme_exception2code(); + err = _gpg_exception2code(); goto leave; } retval = PyObject_CallFunctionObjArgs(func, py_name, py_args, NULL); if (PyErr_Occurred()) - err = _pyme_exception2code(); + err = _gpg_exception2code(); Py_XDECREF(retval); /* FIXME: Returning data is not yet implemented. */ @@ -1121,13 +1121,13 @@ _pyme_assuan_inquire_cb (void *hook, const char *name, const char *args, Py_XDECREF(py_name); Py_XDECREF(py_args); if (err) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); PyGILState_Release(state); return err; } gpgme_error_t -_pyme_assuan_status_cb (void *hook, const char *status, const char *args) +_gpg_assuan_status_cb (void *hook, const char *status, const char *args) { PyGILState_STATE state = PyGILState_Ensure(); gpgme_error_t err = 0; @@ -1147,27 +1147,27 @@ _pyme_assuan_status_cb (void *hook, const char *status, const char *args) py_status = PyUnicode_FromString(status); if (py_status == NULL) { - err = _pyme_exception2code(); + err = _gpg_exception2code(); goto leave; } py_args = PyUnicode_FromString(args); if (py_args == NULL) { - err = _pyme_exception2code(); + err = _gpg_exception2code(); goto leave; } retval = PyObject_CallFunctionObjArgs(func, py_status, py_args, NULL); if (PyErr_Occurred()) - err = _pyme_exception2code(); + err = _gpg_exception2code(); Py_XDECREF(retval); leave: Py_XDECREF(py_status); Py_XDECREF(py_args); if (err) - _pyme_stash_callback_exception(self); + _gpg_stash_callback_exception(self); PyGILState_Release(state); return err; } diff --git a/lang/python/helpers.h b/lang/python/helpers.h index 67d23b2e..61f538e2 100644 --- a/lang/python/helpers.h +++ b/lang/python/helpers.h @@ -31,13 +31,13 @@ #endif /* Flag specifying whether this is an in-tree build. */ -extern int pyme_in_tree_build; +extern int gpg_in_tree_build; -PyObject *pyme_raise_callback_exception(PyObject *self); +PyObject *gpg_raise_callback_exception(PyObject *self); -PyObject *pyme_set_passphrase_cb(PyObject *self, PyObject *cb); -PyObject *pyme_set_progress_cb(PyObject *self, PyObject *cb); -PyObject *pyme_set_status_cb(PyObject *self, PyObject *cb); +PyObject *gpg_set_passphrase_cb(PyObject *self, PyObject *cb); +PyObject *gpg_set_progress_cb(PyObject *self, PyObject *cb); +PyObject *gpg_set_status_cb(PyObject *self, PyObject *cb); -PyObject *pyme_data_new_from_cbs(PyObject *self, PyObject *pycbs, +PyObject *gpg_data_new_from_cbs(PyObject *self, PyObject *pycbs, gpgme_data_t *r_data); diff --git a/lang/python/private.h b/lang/python/private.h index 3a903c18..e7b371f8 100644 --- a/lang/python/private.h +++ b/lang/python/private.h @@ -19,36 +19,36 @@ #include -#ifndef _PYME_PRIVATE_H_ -#define _PYME_PRIVATE_H_ +#ifndef _GPG_PRIVATE_H_ +#define _GPG_PRIVATE_H_ /* GPGME glue. Implemented in helpers.c. */ -void _pyme_exception_init(void); -gpgme_error_t _pyme_exception2code(void); +void _gpg_exception_init(void); +gpgme_error_t _gpg_exception2code(void); -PyObject *_pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum); -PyObject *_pyme_obj2gpgme_data_t(PyObject *input, int argnum, +PyObject *_gpg_obj2gpgme_t(PyObject *input, const char *objtype, int argnum); +PyObject *_gpg_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper, PyObject **bytesio, Py_buffer *view); -PyObject *_pyme_wrap_result(PyObject *fragile, const char *classname); +PyObject *_gpg_wrap_result(PyObject *fragile, const char *classname); -gpgme_error_t _pyme_interact_cb(void *opaque, const char *keyword, +gpgme_error_t _gpg_interact_cb(void *opaque, const char *keyword, const char *args, int fd); -gpgme_error_t _pyme_assuan_data_cb (void *hook, +gpgme_error_t _gpg_assuan_data_cb (void *hook, const void *data, size_t datalen); -gpgme_error_t _pyme_assuan_inquire_cb (void *hook, +gpgme_error_t _gpg_assuan_inquire_cb (void *hook, const char *name, const char *args, gpgme_data_t *r_data); -gpgme_error_t _pyme_assuan_status_cb (void *hook, +gpgme_error_t _gpg_assuan_status_cb (void *hook, const char *status, const char *args); /* SWIG runtime support. Implemented in gpgme.i. */ -PyObject *_pyme_wrap_gpgme_data_t(gpgme_data_t data); -gpgme_ctx_t _pyme_unwrap_gpgme_ctx_t(PyObject *wrapped); +PyObject *_gpg_wrap_gpgme_data_t(gpgme_data_t data); +gpgme_ctx_t _gpg_unwrap_gpgme_ctx_t(PyObject *wrapped); -#endif /* _PYME_PRIVATE_H_ */ +#endif /* _GPG_PRIVATE_H_ */ diff --git a/lang/python/pyme/__init__.py b/lang/python/pyme/__init__.py deleted file mode 100644 index 12c96c28..00000000 --- a/lang/python/pyme/__init__.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (C) 2016 g10 Code GmbH -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -"""Pyme: GPGME Interface for Python - -Welcome to PyME, the GPGME Interface for Python. "Pyme", when prounced, -rhymes with "Pine". - -The latest release of this package may be obtained from -https://www.gnupg.org - -Previous releases of this package for Python 2 can be obtained from -http://pyme.sourceforge.net - -FEATURES --------- - - * Feature-rich, full implementation of the GPGME library. Supports - all GPGME features. Callback functions may be written in pure - Python. Exceptions raised in callbacks are properly propagated. - - * Ability to sign, encrypt, decrypt, and verify data. - - * Ability to list keys, export and import keys, and manage the keyring. - - * Fully object-oriented with convenient classes and modules. - -QUICK EXAMPLE -------------- - - >>> import pyme - >>> with pyme.Context() as c: - >>> with pyme.Context() as c: - ... cipher, _, _ = c.encrypt("Hello world :)".encode(), - ... passphrase="abc") - ... c.decrypt(cipher, passphrase="abc") - ... - (b'Hello world :)', - , - ) - -GENERAL OVERVIEW ----------------- - -For those of you familiar with GPGME, you will be right at home here. - -Pyme is, for the most part, a direct interface to the C GPGME -library. However, it is re-packaged in a more Pythonic way -- -object-oriented with classes and modules. Take a look at the classes -defined here -- they correspond directly to certain object types in GPGME -for C. For instance, the following C code: - -gpgme_ctx_t context; -gpgme_new(&context); -... -gpgme_op_encrypt(context, recp, 1, plain, cipher); - -Translates into the following Python code: - -context = core.Context() -... -context.op_encrypt(recp, 1, plain, cipher) - -The Python module automatically does error-checking and raises Python -exception pyme.errors.GPGMEError when GPGME signals an error. getcode() -and getsource() of this exception return code and source of the error. - -IMPORTANT NOTE --------------- -This documentation only covers a small subset of available GPGME functions and -methods. Please consult the documentation for the C library -for comprehensive coverage. - -This library uses Python's reflection to automatically detect the methods -that are available for each class, and as such, most of those methods -do not appear explicitly anywhere. You can use dir() python built-in command -on an object to see what methods and fields it has but their meaning can -be found only in GPGME documentation. - -FOR MORE INFORMATION --------------------- -PYME3 homepage: https://www.gnupg.org/ -GPGME documentation: https://www.gnupg.org/documentation/manuals/gpgme/ - -""" - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from . import core -from . import errors -from . import constants -from . import util -from . import callbacks -from . import version -from .core import Context -from .core import Data - -# Interface hygiene. - -# Drop the low-level gpgme that creeps in for some reason. -gpgme = None -del gpgme - -# This is a white-list of symbols. Any other will alert pyflakes. -_ = [Context, Data, core, errors, constants, util, callbacks, version] -del _ - -__all__ = ["Context", "Data", - "core", "errors", "constants", "util", "callbacks", "version"] diff --git a/lang/python/pyme/callbacks.py b/lang/python/pyme/callbacks.py deleted file mode 100644 index b25a9a74..00000000 --- a/lang/python/pyme/callbacks.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from getpass import getpass - -def passphrase_stdin(hint, desc, prev_bad, hook=None): - """This is a sample callback that will read a passphrase from - the terminal. The hook here, if present, will be used to describe - why the passphrase is needed.""" - why = '' - if hook != None: - why = ' ' + hook - if prev_bad: - why += ' (again)' - print("Please supply %s' password%s:" % (hint, why)) - return getpass() - -def progress_stdout(what, type, current, total, hook=None): - print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\ - (what, type, current, total)) - -def readcb_fh(count, hook): - """A callback for data. hook should be a Python file-like object.""" - if count: - # Should return '' on EOF - return hook.read(count) - else: - # Wants to rewind. - if not hasattr(hook, 'seek'): - return None - hook.seek(0, 0) - return None diff --git a/lang/python/pyme/constants/__init__.py b/lang/python/pyme/constants/__init__.py deleted file mode 100644 index 96d89e47..00000000 --- a/lang/python/pyme/constants/__init__.py +++ /dev/null @@ -1,114 +0,0 @@ - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_', globals()) - -__all__ = ['data', 'event', 'import', 'keylist', 'md', 'pk', - 'protocol', 'sig', 'sigsum', 'status', 'validity'] - -# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We -# implement pyme.Context.op_edit using gpgme_op_interact, so the -# callbacks will be called with string keywords instead of numeric -# status messages. Code that is using these constants will continue -# to work. - -STATUS_ABORT = "ABORT" -STATUS_ALREADY_SIGNED = "ALREADY_SIGNED" -STATUS_ATTRIBUTE = "ATTRIBUTE" -STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED" -STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE" -STATUS_BADARMOR = "BADARMOR" -STATUS_BADMDC = "BADMDC" -STATUS_BADSIG = "BADSIG" -STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION" -STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION" -STATUS_BEGIN_SIGNING = "BEGIN_SIGNING" -STATUS_BEGIN_STREAM = "BEGIN_STREAM" -STATUS_CARDCTRL = "CARDCTRL" -STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED" -STATUS_DECRYPTION_INFO = "DECRYPTION_INFO" -STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY" -STATUS_DELETE_PROBLEM = "DELETE_PROBLEM" -STATUS_ENC_TO = "ENC_TO" -STATUS_END_DECRYPTION = "END_DECRYPTION" -STATUS_END_ENCRYPTION = "END_ENCRYPTION" -STATUS_END_STREAM = "END_STREAM" -STATUS_ENTER = "ENTER" -STATUS_ERRMDC = "ERRMDC" -STATUS_ERROR = "ERROR" -STATUS_ERRSIG = "ERRSIG" -STATUS_EXPKEYSIG = "EXPKEYSIG" -STATUS_EXPSIG = "EXPSIG" -STATUS_FAILURE = "FAILURE" -STATUS_FILE_DONE = "FILE_DONE" -STATUS_FILE_ERROR = "FILE_ERROR" -STATUS_FILE_START = "FILE_START" -STATUS_GET_BOOL = "GET_BOOL" -STATUS_GET_HIDDEN = "GET_HIDDEN" -STATUS_GET_LINE = "GET_LINE" -STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE" -STATUS_GOODMDC = "GOODMDC" -STATUS_GOODSIG = "GOODSIG" -STATUS_GOT_IT = "GOT_IT" -STATUS_IMPORT_OK = "IMPORT_OK" -STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM" -STATUS_IMPORT_RES = "IMPORT_RES" -STATUS_IMPORTED = "IMPORTED" -STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN" -STATUS_INV_RECP = "INV_RECP" -STATUS_INV_SGNR = "INV_SGNR" -STATUS_KEY_CONSIDERED = "KEY_CONSIDERED" -STATUS_KEY_CREATED = "KEY_CREATED" -STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED" -STATUS_KEYEXPIRED = "KEYEXPIRED" -STATUS_KEYREVOKED = "KEYREVOKED" -STATUS_LEAVE = "LEAVE" -STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE" -STATUS_MOUNTPOINT = "MOUNTPOINT" -STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE" -STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN" -STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM" -STATUS_NEWSIG = "NEWSIG" -STATUS_NO_PUBKEY = "NO_PUBKEY" -STATUS_NO_RECP = "NO_RECP" -STATUS_NO_SECKEY = "NO_SECKEY" -STATUS_NO_SGNR = "NO_SGNR" -STATUS_NODATA = "NODATA" -STATUS_NOTATION_DATA = "NOTATION_DATA" -STATUS_NOTATION_FLAGS = "NOTATION_FLAGS" -STATUS_NOTATION_NAME = "NOTATION_NAME" -STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED" -STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD" -STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD" -STATUS_PLAINTEXT = "PLAINTEXT" -STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH" -STATUS_POLICY_URL = "POLICY_URL" -STATUS_PROGRESS = "PROGRESS" -STATUS_REVKEYSIG = "REVKEYSIG" -STATUS_RSA_OR_IDEA = "RSA_OR_IDEA" -STATUS_SC_OP_FAILURE = "SC_OP_FAILURE" -STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS" -STATUS_SESSION_KEY = "SESSION_KEY" -STATUS_SHM_GET = "SHM_GET" -STATUS_SHM_GET_BOOL = "SHM_GET_BOOL" -STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN" -STATUS_SHM_INFO = "SHM_INFO" -STATUS_SIG_CREATED = "SIG_CREATED" -STATUS_SIG_ID = "SIG_ID" -STATUS_SIG_SUBPACKET = "SIG_SUBPACKET" -STATUS_SIGEXPIRED = "SIGEXPIRED" -STATUS_SUCCESS = "SUCCESS" -STATUS_TOFU_STATS = "TOFU_STATS" -STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG" -STATUS_TOFU_USER = "TOFU_USER" -STATUS_TRUNCATED = "TRUNCATED" -STATUS_TRUST_FULLY = "TRUST_FULLY" -STATUS_TRUST_MARGINAL = "TRUST_MARGINAL" -STATUS_TRUST_NEVER = "TRUST_NEVER" -STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE" -STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED" -STATUS_UNEXPECTED = "UNEXPECTED" -STATUS_USERID_HINT = "USERID_HINT" -STATUS_VALIDSIG = "VALIDSIG" diff --git a/lang/python/pyme/constants/data/__init__.py b/lang/python/pyme/constants/data/__init__.py deleted file mode 100644 index 8274ab91..00000000 --- a/lang/python/pyme/constants/data/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from . import encoding -__all__ = ['encoding'] diff --git a/lang/python/pyme/constants/data/encoding.py b/lang/python/pyme/constants/data/encoding.py deleted file mode 100644 index a05dbb42..00000000 --- a/lang/python/pyme/constants/data/encoding.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_DATA_ENCODING_', globals()) diff --git a/lang/python/pyme/constants/event.py b/lang/python/pyme/constants/event.py deleted file mode 100644 index 2e30c5e1..00000000 --- a/lang/python/pyme/constants/event.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_EVENT_', globals()) diff --git a/lang/python/pyme/constants/import.py b/lang/python/pyme/constants/import.py deleted file mode 100644 index 10e7d3c0..00000000 --- a/lang/python/pyme/constants/import.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_IMPORT_', globals()) diff --git a/lang/python/pyme/constants/keylist/__init__.py b/lang/python/pyme/constants/keylist/__init__.py deleted file mode 100644 index 2ce0edfd..00000000 --- a/lang/python/pyme/constants/keylist/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from . import mode -__all__ = ['mode'] diff --git a/lang/python/pyme/constants/keylist/mode.py b/lang/python/pyme/constants/keylist/mode.py deleted file mode 100644 index 000dd791..00000000 --- a/lang/python/pyme/constants/keylist/mode.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_KEYLIST_MODE_', globals()) diff --git a/lang/python/pyme/constants/md.py b/lang/python/pyme/constants/md.py deleted file mode 100644 index dbd762ce..00000000 --- a/lang/python/pyme/constants/md.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_MD_', globals()) diff --git a/lang/python/pyme/constants/pk.py b/lang/python/pyme/constants/pk.py deleted file mode 100644 index cfc53095..00000000 --- a/lang/python/pyme/constants/pk.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_PK_', globals()) diff --git a/lang/python/pyme/constants/protocol.py b/lang/python/pyme/constants/protocol.py deleted file mode 100644 index a4b6583a..00000000 --- a/lang/python/pyme/constants/protocol.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_PROTOCOL_', globals()) diff --git a/lang/python/pyme/constants/sig/__init__.py b/lang/python/pyme/constants/sig/__init__.py deleted file mode 100644 index 2ce0edfd..00000000 --- a/lang/python/pyme/constants/sig/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from . import mode -__all__ = ['mode'] diff --git a/lang/python/pyme/constants/sig/mode.py b/lang/python/pyme/constants/sig/mode.py deleted file mode 100644 index fb534bc5..00000000 --- a/lang/python/pyme/constants/sig/mode.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_SIG_MODE_', globals()) diff --git a/lang/python/pyme/constants/sigsum.py b/lang/python/pyme/constants/sigsum.py deleted file mode 100644 index 3d947456..00000000 --- a/lang/python/pyme/constants/sigsum.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_SIGSUM_', globals()) diff --git a/lang/python/pyme/constants/status.py b/lang/python/pyme/constants/status.py deleted file mode 100644 index a04d9aae..00000000 --- a/lang/python/pyme/constants/status.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We -# implement pyme.Context.op_edit using gpgme_op_interact, so the -# callbacks will be called with string keywords instead of numeric -# status messages. Code that is using these constants will continue -# to work. - -ABORT = "ABORT" -ALREADY_SIGNED = "ALREADY_SIGNED" -ATTRIBUTE = "ATTRIBUTE" -BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED" -BAD_PASSPHRASE = "BAD_PASSPHRASE" -BADARMOR = "BADARMOR" -BADMDC = "BADMDC" -BADSIG = "BADSIG" -BEGIN_DECRYPTION = "BEGIN_DECRYPTION" -BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION" -BEGIN_SIGNING = "BEGIN_SIGNING" -BEGIN_STREAM = "BEGIN_STREAM" -CARDCTRL = "CARDCTRL" -DECRYPTION_FAILED = "DECRYPTION_FAILED" -DECRYPTION_INFO = "DECRYPTION_INFO" -DECRYPTION_OKAY = "DECRYPTION_OKAY" -DELETE_PROBLEM = "DELETE_PROBLEM" -ENC_TO = "ENC_TO" -END_DECRYPTION = "END_DECRYPTION" -END_ENCRYPTION = "END_ENCRYPTION" -END_STREAM = "END_STREAM" -ENTER = "ENTER" -ERRMDC = "ERRMDC" -ERROR = "ERROR" -ERRSIG = "ERRSIG" -EXPKEYSIG = "EXPKEYSIG" -EXPSIG = "EXPSIG" -FAILURE = "FAILURE" -FILE_DONE = "FILE_DONE" -FILE_ERROR = "FILE_ERROR" -FILE_START = "FILE_START" -GET_BOOL = "GET_BOOL" -GET_HIDDEN = "GET_HIDDEN" -GET_LINE = "GET_LINE" -GOOD_PASSPHRASE = "GOOD_PASSPHRASE" -GOODMDC = "GOODMDC" -GOODSIG = "GOODSIG" -GOT_IT = "GOT_IT" -IMPORT_OK = "IMPORT_OK" -IMPORT_PROBLEM = "IMPORT_PROBLEM" -IMPORT_RES = "IMPORT_RES" -IMPORTED = "IMPORTED" -INQUIRE_MAXLEN = "INQUIRE_MAXLEN" -INV_RECP = "INV_RECP" -INV_SGNR = "INV_SGNR" -KEY_CONSIDERED = "KEY_CONSIDERED" -KEY_CREATED = "KEY_CREATED" -KEY_NOT_CREATED = "KEY_NOT_CREATED" -KEYEXPIRED = "KEYEXPIRED" -KEYREVOKED = "KEYREVOKED" -LEAVE = "LEAVE" -MISSING_PASSPHRASE = "MISSING_PASSPHRASE" -MOUNTPOINT = "MOUNTPOINT" -NEED_PASSPHRASE = "NEED_PASSPHRASE" -NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN" -NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM" -NEWSIG = "NEWSIG" -NO_PUBKEY = "NO_PUBKEY" -NO_RECP = "NO_RECP" -NO_SECKEY = "NO_SECKEY" -NO_SGNR = "NO_SGNR" -NODATA = "NODATA" -NOTATION_DATA = "NOTATION_DATA" -NOTATION_FLAGS = "NOTATION_FLAGS" -NOTATION_NAME = "NOTATION_NAME" -PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED" -PKA_TRUST_BAD = "PKA_TRUST_BAD" -PKA_TRUST_GOOD = "PKA_TRUST_GOOD" -PLAINTEXT = "PLAINTEXT" -PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH" -POLICY_URL = "POLICY_URL" -PROGRESS = "PROGRESS" -REVKEYSIG = "REVKEYSIG" -RSA_OR_IDEA = "RSA_OR_IDEA" -SC_OP_FAILURE = "SC_OP_FAILURE" -SC_OP_SUCCESS = "SC_OP_SUCCESS" -SESSION_KEY = "SESSION_KEY" -SHM_GET = "SHM_GET" -SHM_GET_BOOL = "SHM_GET_BOOL" -SHM_GET_HIDDEN = "SHM_GET_HIDDEN" -SHM_INFO = "SHM_INFO" -SIG_CREATED = "SIG_CREATED" -SIG_ID = "SIG_ID" -SIG_SUBPACKET = "SIG_SUBPACKET" -SIGEXPIRED = "SIGEXPIRED" -SUCCESS = "SUCCESS" -TOFU_STATS = "TOFU_STATS" -TOFU_STATS_LONG = "TOFU_STATS_LONG" -TOFU_USER = "TOFU_USER" -TRUNCATED = "TRUNCATED" -TRUST_FULLY = "TRUST_FULLY" -TRUST_MARGINAL = "TRUST_MARGINAL" -TRUST_NEVER = "TRUST_NEVER" -TRUST_ULTIMATE = "TRUST_ULTIMATE" -TRUST_UNDEFINED = "TRUST_UNDEFINED" -UNEXPECTED = "UNEXPECTED" -USERID_HINT = "USERID_HINT" -VALIDSIG = "VALIDSIG" diff --git a/lang/python/pyme/constants/validity.py b/lang/python/pyme/constants/validity.py deleted file mode 100644 index 4ecd4d3e..00000000 --- a/lang/python/pyme/constants/validity.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from pyme import util -util.process_constants('GPGME_VALIDITY_', globals()) diff --git a/lang/python/pyme/core.py b/lang/python/pyme/core.py deleted file mode 100644 index f0eab436..00000000 --- a/lang/python/pyme/core.py +++ /dev/null @@ -1,1164 +0,0 @@ -# Copyright (C) 2016 g10 Code GmbH -# Copyright (C) 2004,2008 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -"""Core functionality - -Core functionality of GPGME wrapped in a object-oriented fashion. -Provides the 'Context' class for performing cryptographic operations, -and the 'Data' class describing buffers of data. - -""" - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -import re -import os -import warnings -import weakref -from . import gpgme -from .errors import errorcheck, GPGMEError -from . import constants -from . import errors -from . import util - -class GpgmeWrapper(object): - """Base wrapper class - - Not to be instantiated directly. - - """ - - def __init__(self, wrapped): - self._callback_excinfo = None - self.wrapped = wrapped - - def __repr__(self): - return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(), - self.wrapped) - - def __str__(self): - acc = ['{}.{}'.format(__name__, self.__class__.__name__)] - flags = [f for f in self._boolean_properties if getattr(self, f)] - if flags: - acc.append('({})'.format(' '.join(flags))) - - return '<{}>'.format(' '.join(acc)) - - def __hash__(self): - return hash(repr(self.wrapped)) - - def __eq__(self, other): - if other == None: - return False - else: - return repr(self.wrapped) == repr(other.wrapped) - - @property - def _ctype(self): - """The name of the c type wrapped by this class - - Must be set by child classes. - - """ - raise NotImplementedError() - - @property - def _cprefix(self): - """The common prefix of c functions wrapped by this class - - Must be set by child classes. - - """ - raise NotImplementedError() - - def _errorcheck(self, name): - """Must be implemented by child classes. - - This function must return a trueish value for all c functions - returning gpgme_error_t.""" - raise NotImplementedError() - - """The set of all boolean properties""" - _boolean_properties = set() - - def __wrap_boolean_property(self, key, do_set=False, value=None): - get_func = getattr(gpgme, - "{}get_{}".format(self._cprefix, key)) - set_func = getattr(gpgme, - "{}set_{}".format(self._cprefix, key)) - def get(slf): - return bool(get_func(slf.wrapped)) - def set_(slf, value): - set_func(slf.wrapped, bool(value)) - - p = property(get, set_, doc="{} flag".format(key)) - setattr(self.__class__, key, p) - - if do_set: - set_(self, bool(value)) - else: - return get(self) - - _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)') - def __getattr__(self, key): - """On-the-fly generation of wrapper methods and properties""" - if key[0] == '_' or self._cprefix == None: - return None - - if key in self._boolean_properties: - return self.__wrap_boolean_property(key) - - name = self._cprefix + key - func = getattr(gpgme, name) - - if self._errorcheck(name): - def _funcwrap(slf, *args): - result = func(slf.wrapped, *args) - if slf._callback_excinfo: - gpgme.pyme_raise_callback_exception(slf) - return errorcheck(result, "Invocation of " + name) - else: - def _funcwrap(slf, *args): - result = func(slf.wrapped, *args) - if slf._callback_excinfo: - gpgme.pyme_raise_callback_exception(slf) - return result - - doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__")) - _funcwrap.__doc__ = doc - - # Monkey-patch the class. - setattr(self.__class__, key, _funcwrap) - - # Bind the method to 'self'. - def wrapper(*args): - return _funcwrap(self, *args) - wrapper.__doc__ = doc - - return wrapper - - def __setattr__(self, key, value): - """On-the-fly generation of properties""" - if key in self._boolean_properties: - self.__wrap_boolean_property(key, True, value) - else: - super(GpgmeWrapper, self).__setattr__(key, value) - -class Context(GpgmeWrapper): - """Context for cryptographic operations - - All cryptographic operations in GPGME are performed within a - context, which contains the internal state of the operation as - well as configuration parameters. By using several contexts you - can run several cryptographic operations in parallel, with - different configuration. - - Access to a context must be synchronized. - - """ - - def __init__(self, armor=False, textmode=False, offline=False, - signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT, - protocol=constants.PROTOCOL_OpenPGP, - wrapped=None): - """Construct a context object - - Keyword arguments: - armor -- enable ASCII armoring (default False) - textmode -- enable canonical text mode (default False) - offline -- do not contact external key sources (default False) - signers -- list of keys used for signing (default []) - pinentry_mode -- pinentry mode (default PINENTRY_MODE_DEFAULT) - protocol -- protocol to use (default PROTOCOL_OpenPGP) - - """ - if wrapped: - self.own = False - else: - tmp = gpgme.new_gpgme_ctx_t_p() - errorcheck(gpgme.gpgme_new(tmp)) - wrapped = gpgme.gpgme_ctx_t_p_value(tmp) - gpgme.delete_gpgme_ctx_t_p(tmp) - self.own = True - super(Context, self).__init__(wrapped) - self.armor = armor - self.textmode = textmode - self.offline = offline - self.signers = signers - self.pinentry_mode = pinentry_mode - self.protocol = protocol - - def encrypt(self, plaintext, recipients=[], sign=True, sink=None, - passphrase=None, always_trust=False, add_encrypt_to=False, - prepare=False, expect_sign=False, compress=True): - """Encrypt data - - Encrypt the given plaintext for the given recipients. If the - list of recipients is empty, the data is encrypted - symmetrically with a passphrase. - - The passphrase can be given as parameter, using a callback - registered at the context, or out-of-band via pinentry. - - Keyword arguments: - recipients -- list of keys to encrypt to - sign -- sign plaintext (default True) - sink -- write result to sink instead of returning it - passphrase -- for symmetric encryption - always_trust -- always trust the keys (default False) - add_encrypt_to -- encrypt to configured additional keys (default False) - prepare -- (ui) prepare for encryption (default False) - expect_sign -- (ui) prepare for signing (default False) - compress -- compress plaintext (default True) - - Returns: - ciphertext -- the encrypted data (or None if sink is given) - result -- additional information about the encryption - sign_result -- additional information about the signature(s) - - Raises: - InvalidRecipients -- if encryption using a particular key failed - InvalidSigners -- if signing using a particular key failed - GPGMEError -- as signaled by the underlying library - - """ - ciphertext = sink if sink else Data() - flags = 0 - flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST - flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO - flags |= prepare * constants.ENCRYPT_PREPARE - flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN - flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS - - if passphrase != None: - old_pinentry_mode = self.pinentry_mode - old_passphrase_cb = getattr(self, '_passphrase_cb', None) - self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK - def passphrase_cb(hint, desc, prev_bad, hook=None): - return passphrase - self.set_passphrase_cb(passphrase_cb) - - try: - if sign: - self.op_encrypt_sign(recipients, flags, plaintext, ciphertext) - else: - self.op_encrypt(recipients, flags, plaintext, ciphertext) - except errors.GPGMEError as e: - if e.getcode() == errors.UNUSABLE_PUBKEY: - result = self.op_encrypt_result() - if result.invalid_recipients: - raise errors.InvalidRecipients(result.invalid_recipients) - if e.getcode() == errors.UNUSABLE_SECKEY: - sig_result = self.op_sign_result() - if sig_result.invalid_signers: - raise errors.InvalidSigners(sig_result.invalid_signers) - raise - finally: - if passphrase != None: - self.pinentry_mode = old_pinentry_mode - if old_passphrase_cb: - self.set_passphrase_cb(*old_passphrase_cb[1:]) - - result = self.op_encrypt_result() - assert not result.invalid_recipients - sig_result = self.op_sign_result() if sign else None - assert not sig_result or not sig_result.invalid_signers - - cipherbytes = None - if not sink: - ciphertext.seek(0, os.SEEK_SET) - cipherbytes = ciphertext.read() - return cipherbytes, result, sig_result - - def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True): - """Decrypt data - - Decrypt the given ciphertext and verify any signatures. If - VERIFY is an iterable of keys, the ciphertext must be signed - by all those keys, otherwise an error is raised. - - If the ciphertext is symmetrically encrypted using a - passphrase, that passphrase can be given as parameter, using a - callback registered at the context, or out-of-band via - pinentry. - - Keyword arguments: - sink -- write result to sink instead of returning it - passphrase -- for symmetric decryption - verify -- check signatures (default True) - - Returns: - plaintext -- the decrypted data (or None if sink is given) - result -- additional information about the decryption - verify_result -- additional information about the signature(s) - - Raises: - UnsupportedAlgorithm -- if an unsupported algorithm was used - BadSignatures -- if a bad signature is encountered - MissingSignatures -- if expected signatures are missing or bad - GPGMEError -- as signaled by the underlying library - - """ - plaintext = sink if sink else Data() - - if passphrase != None: - old_pinentry_mode = self.pinentry_mode - old_passphrase_cb = getattr(self, '_passphrase_cb', None) - self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK - def passphrase_cb(hint, desc, prev_bad, hook=None): - return passphrase - self.set_passphrase_cb(passphrase_cb) - - try: - if verify: - self.op_decrypt_verify(ciphertext, plaintext) - else: - self.op_decrypt(ciphertext, plaintext) - finally: - if passphrase != None: - self.pinentry_mode = old_pinentry_mode - if old_passphrase_cb: - self.set_passphrase_cb(*old_passphrase_cb[1:]) - - result = self.op_decrypt_result() - verify_result = self.op_verify_result() if verify else None - if result.unsupported_algorithm: - raise errors.UnsupportedAlgorithm(result.unsupported_algorithm) - - if verify: - if any(s.status != errors.NO_ERROR - for s in verify_result.signatures): - raise errors.BadSignatures(verify_result) - - if verify and verify != True: - missing = list() - for key in verify: - ok = False - for subkey in key.subkeys: - for sig in verify_result.signatures: - if sig.summary & constants.SIGSUM_VALID == 0: - continue - if subkey.can_sign and subkey.fpr == sig.fpr: - ok = True - break - if ok: - break - if not ok: - missing.append(key) - if missing: - raise errors.MissingSignatures(verify_result, missing) - - plainbytes = None - if not sink: - plaintext.seek(0, os.SEEK_SET) - plainbytes = plaintext.read() - return plainbytes, result, verify_result - - def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL): - """Sign data - - Sign the given data with either the configured default local - key, or the 'signers' keys of this context. - - Keyword arguments: - mode -- signature mode (default: normal, see below) - sink -- write result to sink instead of returning it - - Returns: - either - signed_data -- encoded data and signature (normal mode) - signature -- only the signature data (detached mode) - cleartext -- data and signature as text (cleartext mode) - (or None if sink is given) - result -- additional information about the signature(s) - - Raises: - InvalidSigners -- if signing using a particular key failed - GPGMEError -- as signaled by the underlying library - - """ - signeddata = sink if sink else Data() - - try: - self.op_sign(data, signeddata, mode) - except errors.GPGMEError as e: - if e.getcode() == errors.UNUSABLE_SECKEY: - result = self.op_sign_result() - if result.invalid_signers: - raise errors.InvalidSigners(result.invalid_signers) - raise - - result = self.op_sign_result() - assert not result.invalid_signers - - signedbytes = None - if not sink: - signeddata.seek(0, os.SEEK_SET) - signedbytes = signeddata.read() - return signedbytes, result - - def verify(self, signed_data, signature=None, sink=None, verify=[]): - """Verify signatures - - Verify signatures over data. If VERIFY is an iterable of - keys, the ciphertext must be signed by all those keys, - otherwise an error is raised. - - Keyword arguments: - signature -- detached signature data - sink -- write result to sink instead of returning it - - Returns: - data -- the plain data - (or None if sink is given, or we verified a detached signature) - result -- additional information about the signature(s) - - Raises: - BadSignatures -- if a bad signature is encountered - MissingSignatures -- if expected signatures are missing or bad - GPGMEError -- as signaled by the underlying library - - """ - if signature: - # Detached signature, we don't return the plain text. - data = None - else: - data = sink if sink else Data() - - if signature: - self.op_verify(signature, signed_data, None) - else: - self.op_verify(signed_data, None, data) - - result = self.op_verify_result() - if any(s.status != errors.NO_ERROR for s in result.signatures): - raise errors.BadSignatures(result) - - missing = list() - for key in verify: - ok = False - for subkey in key.subkeys: - for sig in result.signatures: - if sig.summary & constants.SIGSUM_VALID == 0: - continue - if subkey.can_sign and subkey.fpr == sig.fpr: - ok = True - break - if ok: - break - if not ok: - missing.append(key) - if missing: - raise errors.MissingSignatures(result, missing) - - plainbytes = None - if data and not sink: - data.seek(0, os.SEEK_SET) - plainbytes = data.read() - return plainbytes, result - - def keylist(self, pattern=None, secret=False): - """List keys - - Keyword arguments: - pattern -- return keys matching pattern (default: all keys) - secret -- return only secret keys - - Returns: - -- an iterator returning key objects - - Raises: - GPGMEError -- as signaled by the underlying library - """ - return self.op_keylist_all(pattern, secret) - - def assuan_transact(self, command, - data_cb=None, inquire_cb=None, status_cb=None): - """Issue a raw assuan command - - This function can be used to issue a raw assuan command to the - engine. - - If command is a string or bytes, it will be used as-is. If it - is an iterable of strings, it will be properly escaped and - joined into an well-formed assuan command. - - Keyword arguments: - data_cb -- a callback receiving data lines - inquire_cb -- a callback providing more information - status_cb -- a callback receiving status lines - - Returns: - result -- the result of command as GPGMEError - - Raises: - GPGMEError -- as signaled by the underlying library - - """ - - if isinstance(command, (str, bytes)): - cmd = command - else: - cmd = " ".join(util.percent_escape(f) for f in command) - - errptr = gpgme.new_gpgme_error_t_p() - - err = gpgme.gpgme_op_assuan_transact_ext( - self.wrapped, - cmd, - (weakref.ref(self), data_cb) if data_cb else None, - (weakref.ref(self), inquire_cb) if inquire_cb else None, - (weakref.ref(self), status_cb) if status_cb else None, - errptr) - - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - - errorcheck(err) - - status = gpgme.gpgme_error_t_p_value(errptr) - gpgme.delete_gpgme_error_t_p(errptr) - - return GPGMEError(status) if status != 0 else None - - def interact(self, key, func, sink=None, flags=0, fnc_value=None): - """Interact with the engine - - This method can be used to edit keys and cards interactively. - KEY is the key to edit, FUNC is called repeatedly with two - unicode arguments, 'keyword' and 'args'. See the GPGME manual - for details. - - Keyword arguments: - sink -- if given, additional output is written here - flags -- use constants.INTERACT_CARD to edit a card - - Raises: - GPGMEError -- as signaled by the underlying library - - """ - if key == None: - raise ValueError("First argument cannot be None") - - if sink == None: - sink = Data() - - if fnc_value: - opaquedata = (weakref.ref(self), func, fnc_value) - else: - opaquedata = (weakref.ref(self), func) - - result = gpgme.gpgme_op_interact(self.wrapped, key, flags, - opaquedata, sink) - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - errorcheck(result) - - @property - def signers(self): - """Keys used for signing""" - return [self.signers_enum(i) for i in range(self.signers_count())] - @signers.setter - def signers(self, signers): - old = self.signers - self.signers_clear() - try: - for key in signers: - self.signers_add(key) - except: - self.signers = old - raise - - @property - def pinentry_mode(self): - """Pinentry mode""" - return self.get_pinentry_mode() - @pinentry_mode.setter - def pinentry_mode(self, value): - self.set_pinentry_mode(value) - - @property - def protocol(self): - """Protocol to use""" - return self.get_protocol() - @protocol.setter - def protocol(self, value): - errorcheck(gpgme.gpgme_engine_check_version(value)) - self.set_protocol(value) - - _ctype = 'gpgme_ctx_t' - _cprefix = 'gpgme_' - - def _errorcheck(self, name): - """This function should list all functions returning gpgme_error_t""" - return ((name.startswith('gpgme_op_') - and not name.endswith('_result')) - or name in { - 'gpgme_set_ctx_flag', - 'gpgme_set_protocol', - 'gpgme_set_sub_protocol', - 'gpgme_set_keylist_mode', - 'gpgme_set_pinentry_mode', - 'gpgme_set_locale', - 'gpgme_set_engine_info', - 'gpgme_signers_add', - 'gpgme_get_sig_key', - 'gpgme_sig_notation_add', - 'gpgme_cancel', - 'gpgme_cancel_async', - 'gpgme_cancel_get_key', - }) - - _boolean_properties = {'armor', 'textmode', 'offline'} - - def __del__(self): - if not gpgme: - # At interpreter shutdown, gpgme is set to NONE. - return - - self._free_passcb() - self._free_progresscb() - self._free_statuscb() - if self.own and self.wrapped and gpgme.gpgme_release: - gpgme.gpgme_release(self.wrapped) - self.wrapped = None - - # Implement the context manager protocol. - def __enter__(self): - return self - def __exit__(self, type, value, tb): - self.__del__() - - def op_keylist_all(self, *args, **kwargs): - self.op_keylist_start(*args, **kwargs) - key = self.op_keylist_next() - while key: - yield key - key = self.op_keylist_next() - self.op_keylist_end() - - def op_keylist_next(self): - """Returns the next key in the list created - by a call to op_keylist_start(). The object returned - is of type Key.""" - ptr = gpgme.new_gpgme_key_t_p() - try: - errorcheck(gpgme.gpgme_op_keylist_next(self.wrapped, ptr)) - key = gpgme.gpgme_key_t_p_value(ptr) - except errors.GPGMEError as excp: - key = None - if excp.getcode() != errors.EOF: - raise excp - gpgme.delete_gpgme_key_t_p(ptr) - if key: - key.__del__ = lambda self: gpgme.gpgme_key_unref(self) - return key - - def get_key(self, fpr, secret=False): - """Get a key given a fingerprint - - Keyword arguments: - secret -- to request a secret key - - Returns: - -- the matching key - - Raises: - KeyError -- if the key was not found - GPGMEError -- as signaled by the underlying library - - """ - ptr = gpgme.new_gpgme_key_t_p() - - try: - errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret)) - except errors.GPGMEError as e: - if e.getcode() == errors.EOF: - raise errors.KeyNotFound(fpr) - raise e - - key = gpgme.gpgme_key_t_p_value(ptr) - gpgme.delete_gpgme_key_t_p(ptr) - assert key - key.__del__ = lambda self: gpgme.gpgme_key_unref(self) - return key - - def op_trustlist_all(self, *args, **kwargs): - self.op_trustlist_start(*args, **kwargs) - trust = self.op_trustlist_next() - while trust: - yield trust - trust = self.op_trustlist_next() - self.op_trustlist_end() - - def op_trustlist_next(self): - """Returns the next trust item in the list created - by a call to op_trustlist_start(). The object returned - is of type TrustItem.""" - ptr = gpgme.new_gpgme_trust_item_t_p() - try: - errorcheck(gpgme.gpgme_op_trustlist_next(self.wrapped, ptr)) - trust = gpgme.gpgme_trust_item_t_p_value(ptr) - except errors.GPGMEError as excp: - trust = None - if excp.getcode() != errors.EOF: - raise - gpgme.delete_gpgme_trust_item_t_p(ptr) - return trust - - def set_passphrase_cb(self, func, hook=None): - """Sets the passphrase callback to the function specified by func. - - When the system needs a passphrase, it will call func with three args: - hint, a string describing the key it needs the passphrase for; - desc, a string describing the passphrase it needs; - prev_bad, a boolean equal True if this is a call made after - unsuccessful previous attempt. - - If hook has a value other than None it will be passed into the func - as a forth argument. - - Please see the GPGME manual for more information. - """ - if func == None: - hookdata = None - else: - if hook == None: - hookdata = (weakref.ref(self), func) - else: - hookdata = (weakref.ref(self), func, hook) - gpgme.pyme_set_passphrase_cb(self, hookdata) - - def _free_passcb(self): - if gpgme.pyme_set_passphrase_cb: - self.set_passphrase_cb(None) - - def set_progress_cb(self, func, hook=None): - """Sets the progress meter callback to the function specified by FUNC. - If FUNC is None, the callback will be cleared. - - This function will be called to provide an interactive update - of the system's progress. The function will be called with - three arguments, type, total, and current. If HOOK is not - None, it will be supplied as fourth argument. - - Please see the GPGME manual for more information. - - """ - if func == None: - hookdata = None - else: - if hook == None: - hookdata = (weakref.ref(self), func) - else: - hookdata = (weakref.ref(self), func, hook) - gpgme.pyme_set_progress_cb(self, hookdata) - - def _free_progresscb(self): - if gpgme.pyme_set_progress_cb: - self.set_progress_cb(None) - - def set_status_cb(self, func, hook=None): - """Sets the status callback to the function specified by FUNC. If - FUNC is None, the callback will be cleared. - - The function will be called with two arguments, keyword and - args. If HOOK is not None, it will be supplied as third - argument. - - Please see the GPGME manual for more information. - - """ - if func == None: - hookdata = None - else: - if hook == None: - hookdata = (weakref.ref(self), func) - else: - hookdata = (weakref.ref(self), func, hook) - gpgme.pyme_set_status_cb(self, hookdata) - - def _free_statuscb(self): - if gpgme.pyme_set_status_cb: - self.set_status_cb(None) - - @property - def engine_info(self): - """Configuration of the engine currently in use""" - p = self.protocol - infos = [i for i in self.get_engine_info() if i.protocol == p] - assert len(infos) == 1 - return infos[0] - - def get_engine_info(self): - """Get engine configuration - - Returns information about all configured and installed - engines. - - Returns: - infos -- a list of engine infos - - """ - return gpgme.gpgme_ctx_get_engine_info(self.wrapped) - - def set_engine_info(self, proto, file_name=None, home_dir=None): - """Change engine configuration - - Changes the configuration of the crypto engine implementing - the protocol 'proto' for the context. - - Keyword arguments: - file_name -- engine program file name (unchanged if None) - home_dir -- configuration directory (unchanged if None) - - """ - errorcheck(gpgme.gpgme_ctx_set_engine_info( - self.wrapped, proto, file_name, home_dir)) - - def wait(self, hang): - """Wait for asynchronous call to finish. Wait forever if hang is True. - Raises an exception on errors. - - Please read the GPGME manual for more information. - - """ - ptr = gpgme.new_gpgme_error_t_p() - gpgme.gpgme_wait(self.wrapped, ptr, hang) - status = gpgme.gpgme_error_t_p_value(ptr) - gpgme.delete_gpgme_error_t_p(ptr) - errorcheck(status) - - def op_edit(self, key, func, fnc_value, out): - """Start key editing using supplied callback function - - Note: This interface is deprecated and will be removed with - GPGME 1.8. Please use .interact instead. Furthermore, we - implement this using gpgme_op_interact, so callbacks will get - called with string keywords instead of numeric status - messages. Code that is using constants.STATUS_X or - constants.status.X will continue to work, whereas code using - magic numbers will break as a result. - - """ - warnings.warn("Call to deprecated method op_edit.", - category=DeprecationWarning) - return self.interact(key, func, sink=out, fnc_value=fnc_value) - - -class Data(GpgmeWrapper): - """Data buffer - - A lot of data has to be exchanged between the user and the crypto - engine, like plaintext messages, ciphertext, signatures and - information about the keys. The technical details about - exchanging the data information are completely abstracted by - GPGME. The user provides and receives the data via `gpgme_data_t' - objects, regardless of the communication protocol between GPGME - and the crypto engine in use. - - This Data class is the implementation of the GpgmeData objects. - - Please see the information about __init__ for instantiation. - - """ - - _ctype = 'gpgme_data_t' - _cprefix = 'gpgme_data_' - - def _errorcheck(self, name): - """This function should list all functions returning gpgme_error_t""" - return name not in { - 'gpgme_data_release_and_get_mem', - 'gpgme_data_get_encoding', - 'gpgme_data_seek', - 'gpgme_data_get_file_name', - } - - def __init__(self, string=None, file=None, offset=None, - length=None, cbs=None, copy=True): - """Initialize a new gpgme_data_t object. - - If no args are specified, make it an empty object. - - If string alone is specified, initialize it with the data - contained there. - - If file, offset, and length are all specified, file must - be either a filename or a file-like object, and the object - will be initialized by reading the specified chunk from the file. - - If cbs is specified, it MUST be a tuple of the form: - - (read_cb, write_cb, seek_cb, release_cb[, hook]) - - where the first four items are functions implementing reading, - writing, seeking the data, and releasing any resources once - the data object is deallocated. The functions must match the - following prototypes: - - def read(amount, hook=None): - return - - def write(data, hook=None): - return - - def seek(offset, whence, hook=None): - return - - def release(hook=None): - - - The functions may be bound methods. In that case, you can - simply use the 'self' reference instead of using a hook. - - If file is specified without any other arguments, then - it must be a filename, and the object will be initialized from - that file. - - """ - super(Data, self).__init__(None) - self.data_cbs = None - - if cbs != None: - self.new_from_cbs(*cbs) - elif string != None: - self.new_from_mem(string, copy) - elif file != None and offset != None and length != None: - self.new_from_filepart(file, offset, length) - elif file != None: - if util.is_a_string(file): - self.new_from_file(file, copy) - else: - self.new_from_fd(file) - else: - self.new() - - def __del__(self): - if not gpgme: - # At interpreter shutdown, gpgme is set to NONE. - return - - if self.wrapped != None and gpgme.gpgme_data_release: - gpgme.gpgme_data_release(self.wrapped) - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - self.wrapped = None - self._free_datacbs() - - # Implement the context manager protocol. - def __enter__(self): - return self - def __exit__(self, type, value, tb): - self.__del__() - - def _free_datacbs(self): - self._data_cbs = None - - def new(self): - tmp = gpgme.new_gpgme_data_t_p() - errorcheck(gpgme.gpgme_data_new(tmp)) - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_mem(self, string, copy=True): - tmp = gpgme.new_gpgme_data_t_p() - errorcheck(gpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy)) - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_file(self, filename, copy=True): - tmp = gpgme.new_gpgme_data_t_p() - try: - errorcheck(gpgme.gpgme_data_new_from_file(tmp, filename, copy)) - except errors.GPGMEError as e: - if e.getcode() == errors.INV_VALUE and not copy: - raise ValueError("delayed reads are not yet supported") - else: - raise e - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None): - tmp = gpgme.new_gpgme_data_t_p() - if hook != None: - hookdata = (weakref.ref(self), - read_cb, write_cb, seek_cb, release_cb, hook) - else: - hookdata = (weakref.ref(self), - read_cb, write_cb, seek_cb, release_cb) - gpgme.pyme_data_new_from_cbs(self, hookdata, tmp) - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_filepart(self, file, offset, length): - """This wraps the GPGME gpgme_data_new_from_filepart() function. - The argument "file" may be: - - * a string specifying a file name, or - * a file-like object supporting the fileno() and the mode attribute. - - """ - - tmp = gpgme.new_gpgme_data_t_p() - filename = None - fp = None - - if util.is_a_string(file): - filename = file - else: - fp = gpgme.fdopen(file.fileno(), file.mode) - if fp == None: - raise ValueError("Failed to open file from %s arg %s" % \ - (str(type(file)), str(file))) - - errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp, - offset, length)) - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_fd(self, file): - """This wraps the GPGME gpgme_data_new_from_fd() function. The - argument "file" must be a file-like object, supporting the - fileno() method. - - """ - tmp = gpgme.new_gpgme_data_t_p() - errorcheck(gpgme.gpgme_data_new_from_fd(tmp, file.fileno())) - self.wrapped = gpgme.gpgme_data_t_p_value(tmp) - gpgme.delete_gpgme_data_t_p(tmp) - - def new_from_stream(self, file): - """This wrap around gpgme_data_new_from_stream is an alias for - new_from_fd() method since in python there's not difference - between file stream and file descriptor""" - self.new_from_fd(file) - - def write(self, buffer): - """Write buffer given as string or bytes. - - If a string is given, it is implicitly encoded using UTF-8.""" - written = gpgme.gpgme_data_write(self.wrapped, buffer) - if written < 0: - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - else: - raise GPGMEError.fromSyserror() - return written - - def read(self, size = -1): - """Read at most size bytes, returned as bytes. - - If the size argument is negative or omitted, read until EOF is reached. - - Returns the data read, or the empty string if there was no data - to read before EOF was reached.""" - - if size == 0: - return '' - - if size > 0: - try: - result = gpgme.gpgme_data_read(self.wrapped, size) - except: - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - else: - raise - return result - else: - chunks = [] - while True: - try: - result = gpgme.gpgme_data_read(self.wrapped, 4096) - except: - if self._callback_excinfo: - gpgme.pyme_raise_callback_exception(self) - else: - raise - if len(result) == 0: - break - chunks.append(result) - return b''.join(chunks) - -def pubkey_algo_name(algo): - return gpgme.gpgme_pubkey_algo_name(algo) - -def hash_algo_name(algo): - return gpgme.gpgme_hash_algo_name(algo) - -def get_protocol_name(proto): - return gpgme.gpgme_get_protocol_name(proto) - -def check_version(version=None): - return gpgme.gpgme_check_version(version) - -# check_version also makes sure that several subsystems are properly -# initialized, and it must be run at least once before invoking any -# other function. We do it here so that the user does not have to do -# it unless she really wants to check for a certain version. -check_version() - -def engine_check_version (proto): - try: - errorcheck(gpgme.gpgme_engine_check_version(proto)) - return True - except errors.GPGMEError: - return False - -def get_engine_info(): - ptr = gpgme.new_gpgme_engine_info_t_p() - try: - errorcheck(gpgme.gpgme_get_engine_info(ptr)) - info = gpgme.gpgme_engine_info_t_p_value(ptr) - except errors.GPGMEError: - info = None - gpgme.delete_gpgme_engine_info_t_p(ptr) - return info - -def set_engine_info(proto, file_name, home_dir=None): - """Changes the default configuration of the crypto engine implementing - the protocol 'proto'. 'file_name' is the file name of - the executable program implementing this protocol. 'home_dir' is the - directory name of the configuration directory (engine's default is - used if omitted).""" - errorcheck(gpgme.gpgme_set_engine_info(proto, file_name, home_dir)) - -def set_locale(category, value): - """Sets the default locale used by contexts""" - errorcheck(gpgme.gpgme_set_locale(None, category, value)) - -def wait(hang): - """Wait for asynchronous call on any Context to finish. - Wait forever if hang is True. - - For finished anynch calls it returns a tuple (status, context): - status - status return by asnynchronous call. - context - context which caused this call to return. - - Please read the GPGME manual of more information.""" - ptr = gpgme.new_gpgme_error_t_p() - context = gpgme.gpgme_wait(None, ptr, hang) - status = gpgme.gpgme_error_t_p_value(ptr) - gpgme.delete_gpgme_error_t_p(ptr) - if context == None: - errorcheck(status) - else: - context = Context(context) - return (status, context) diff --git a/lang/python/pyme/errors.py b/lang/python/pyme/errors.py deleted file mode 100644 index 0fd85efa..00000000 --- a/lang/python/pyme/errors.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2004 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -from . import gpgme -from . import util - -# To appease static analysis tools, we define some constants here. -# They are overwritten with the proper values by process_constants. -NO_ERROR = None -EOF = None - -util.process_constants('GPG_ERR_', globals()) - -class PymeError(Exception): - pass - -class GPGMEError(PymeError): - def __init__(self, error = None, message = None): - self.error = error - self.message = message - - @classmethod - def fromSyserror(cls): - return cls(gpgme.gpgme_err_code_from_syserror()) - - def getstring(self): - message = "%s: %s" % (gpgme.gpgme_strsource(self.error), - gpgme.gpgme_strerror(self.error)) - if self.message != None: - message = "%s: %s" % (self.message, message) - return message - - def getcode(self): - return gpgme.gpgme_err_code(self.error) - - def getsource(self): - return gpgme.gpgme_err_source(self.error) - - def __str__(self): - return self.getstring() - -def errorcheck(retval, extradata = None): - if retval: - raise GPGMEError(retval, extradata) - -class KeyNotFound(GPGMEError, KeyError): - """Raised if a key was not found - - GPGME indicates this condition with EOF, which is not very - idiomatic. We raise this error that is both a GPGMEError - indicating EOF, and a KeyError. - - """ - def __init__(self, keystr): - self.keystr = keystr - GPGMEError.__init__(self, EOF) - def __str__(self): - return self.keystr - -# These errors are raised in the idiomatic interface code. - -class EncryptionError(PymeError): - pass - -class InvalidRecipients(EncryptionError): - def __init__(self, recipients): - self.recipients = recipients - def __str__(self): - return ", ".join("{}: {}".format(r.fpr, - gpgme.gpgme_strerror(r.reason)) - for r in self.recipients) - -class DeryptionError(PymeError): - pass - -class UnsupportedAlgorithm(DeryptionError): - def __init__(self, algorithm): - self.algorithm = algorithm - def __str__(self): - return self.algorithm - -class SigningError(PymeError): - pass - -class InvalidSigners(SigningError): - def __init__(self, signers): - self.signers = signers - def __str__(self): - return ", ".join("{}: {}".format(s.fpr, - gpgme.gpgme_strerror(s.reason)) - for s in self.signers) - -class VerificationError(PymeError): - pass - -class BadSignatures(VerificationError): - def __init__(self, result): - self.result = result - def __str__(self): - return ", ".join("{}: {}".format(s.fpr, - gpgme.gpgme_strerror(s.status)) - for s in self.result.signatures - if s.status != NO_ERROR) - -class MissingSignatures(VerificationError): - def __init__(self, result, missing): - self.result = result - self.missing = missing - def __str__(self): - return ", ".join(k.subkeys[0].fpr for k in self.missing) diff --git a/lang/python/pyme/results.py b/lang/python/pyme/results.py deleted file mode 100644 index 3383896b..00000000 --- a/lang/python/pyme/results.py +++ /dev/null @@ -1,118 +0,0 @@ -# Robust result objects -# -# 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 Lesser General Public License as -# published by the Free Software Foundation; either version 2.1 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 - -"""Robust result objects - -Results returned by the underlying library are fragile, i.e. they are -only valid until the next operation is performed in the context. - -We cannot arbitrarily constrain the lifetime of Python objects, we -therefore create deep copies of the results. - -""" - -class Result(object): - """Result object - - Describes the result of an operation. - - """ - - """Convert to types""" - _type = {} - - """Map functions over list attributes""" - _map = {} - - """Automatically copy unless blacklisted""" - _blacklist = { - 'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown', - } - def __init__(self, fragile): - for key, func in self._type.items(): - if hasattr(fragile, key): - setattr(self, key, func(getattr(fragile, key))) - - for key, func in self._map.items(): - if hasattr(fragile, key): - setattr(self, key, list(map(func, getattr(fragile, key)))) - - for key in dir(fragile): - if key.startswith('_') or key in self._blacklist: - continue - if hasattr(self, key): - continue - - setattr(self, key, getattr(fragile, key)) - - def __str__(self): - return '<{} {}>'.format( - self.__class__.__name__, - ', '.join('{}: {}'.format(k, getattr(self, k)) - for k in dir(self) if not k.startswith('_'))) - -class InvalidKey(Result): - pass - -class EncryptResult(Result): - _map = dict(invalid_recipients=InvalidKey) - -class Recipient(Result): - pass - -class DecryptResult(Result): - _type = dict(wrong_key_usage=bool) - _map = dict(recipients=Recipient) - -class NewSignature(Result): - pass - -class SignResult(Result): - _map = dict(invalid_signers=InvalidKey, signatures=NewSignature) - -class Notation(Result): - pass - -class Signature(Result): - _type = dict(wrong_key_usage=bool, chain_model=bool) - _map = dict(notations=Notation) - -class VerifyResult(Result): - _map = dict(signatures=Signature) - -class ImportStatus(Result): - pass - -class ImportResult(Result): - _map = dict(imports=ImportStatus) - -class GenkeyResult(Result): - _type = dict(primary=bool, sub=bool) - -class KeylistResult(Result): - _type = dict(truncated=bool) - -class VFSMountResult(Result): - pass - -class EngineInfo(Result): - pass diff --git a/lang/python/pyme/util.py b/lang/python/pyme/util.py deleted file mode 100644 index e4fca4c1..00000000 --- a/lang/python/pyme/util.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 2016 g10 Code GmbH -# Copyright (C) 2004,2008 Igor Belyi -# Copyright (C) 2002 John Goerzen -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function, unicode_literals -del absolute_import, print_function, unicode_literals - -import sys - -def process_constants(prefix, scope): - """Called by the constant modules to load up the constants from the C - library starting with PREFIX. Matching constants will be inserted - into SCOPE with PREFIX stripped from the names. Returns the names - of inserted constants. - - """ - from . import gpgme - index = len(prefix) - constants = {identifier[index:]: getattr(gpgme, identifier) - for identifier in dir(gpgme) - if identifier.startswith(prefix)} - scope.update(constants) - return list(constants.keys()) - -def percent_escape(s): - return ''.join( - '%{0:2x}'.format(ord(c)) - if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c - for c in s) - -# Python2/3 compatibility -if sys.version_info[0] == 3: - # Python3 - def is_a_string(x): - return isinstance(x, str) -else: - # Python2 - def is_a_string(x): - return isinstance(x, basestring) diff --git a/lang/python/pyme/version.py.in b/lang/python/pyme/version.py.in deleted file mode 100644 index cfb95100..00000000 --- a/lang/python/pyme/version.py.in +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (C) 2016 g10 Code GmbH -# Copyright (C) 2015 Ben McGinnes -# Copyright (C) 2004 Igor Belyi -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from __future__ import absolute_import, print_function -del absolute_import, print_function - -from . import gpgme - -productname = 'pyme' -versionstr = "@VERSION@" -gpgme_versionstr = gpgme.GPGME_VERSION -in_tree_build = bool(gpgme.cvar.pyme_in_tree_build) - -versionlist = versionstr.split(".") -major = versionlist[0] -minor = versionlist[1] -patch = versionlist[2] - -copyright = """\ -Copyright (C) 2016 g10 Code GmbH -Copyright (C) 2015 Ben McGinnes -Copyright (C) 2014-2015 Martin Albrecht -Copyright (C) 2004-2008 Igor Belyi -Copyright (C) 2002 John Goerzen""" - -author = "The GnuPG hackers" -author_email = "gnupg-devel@gnupg.org" - -description = "Python support for GPGME GnuPG cryptography library" -homepage = "https://gnupg.org" - -license = """Copyright (C) 2016 g10 Code GmbH -Copyright (C) 2015 Ben McGinnes -Copyright (C) 2014, 2015 Martin Albrecht -Copyright (C) 2004, 2008 Igor Belyi -Copyright (C) 2002 John Goerzen - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA""" - -# Interface hygiene. Keep this at the end. -del gpgme diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in index 4c41673a..3d0b7305 100755 --- a/lang/python/setup.py.in +++ b/lang/python/setup.py.in @@ -23,7 +23,7 @@ import os, os.path, sys import glob import subprocess -# Out-of-tree build of the pyme3 bindings. +# Out-of-tree build of the gpg bindings. gpg_error_config = ["gpg-error-config"] gpgme_config_flags = ["--thread=pthread"] gpgme_config = ["gpgme-config"] + gpgme_config_flags @@ -88,7 +88,7 @@ if not os.path.exists(gpg_error_h): glob.glob(os.path.join(gpg_error_prefix, "include", "*", "gpg-error.h"))[0] -print("Building pyme3 using {} and {}.".format(gpgme_h, gpg_error_h)) +print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h)) # Cleanup gpgme.h from deprecated functions and typedefs. subprocess.check_call([sys.executable, "gpgme-h-clean.py", gpgme_h], @@ -152,15 +152,15 @@ class BuildExtFirstHack(build): self.run_command('build_ext') build.run(self) -swige = Extension("pyme._gpgme", ["gpgme.i", "helpers.c"], +swige = Extension("gpg._gpgme", ["gpgme.i", "helpers.c"], swig_opts = ['-py3', '-builtin', '-threads', - '-outdir', 'pyme'] + extra_swig_opts, + '-outdir', 'gpg'] + extra_swig_opts, include_dirs = include_dirs, define_macros = define_macros, library_dirs = library_dirs, extra_link_args = libs) -setup(name="pyme3", +setup(name="gpg", cmdclass={'build': BuildExtFirstHack}, version="@VERSION@", description='Python bindings for GPGME GnuPG cryptography library', @@ -170,8 +170,8 @@ setup(name="pyme3", author_email='gnupg-devel@gnupg.org', url='https://www.gnupg.org', ext_modules=[swige], - packages = ['pyme', 'pyme.constants', 'pyme.constants.data', - 'pyme.constants.keylist', 'pyme.constants.sig'], + packages = ['gpg', 'gpg.constants', 'gpg.constants.data', + 'gpg.constants.keylist', 'gpg.constants.sig'], license="LGPL2.1+ (the library), GPL2+ (tests and examples)", classifiers=[ 'Development Status :: 4 - Beta', diff --git a/lang/python/tests/initial.py b/lang/python/tests/initial.py index 2d4827a0..a811a936 100755 --- a/lang/python/tests/initial.py +++ b/lang/python/tests/initial.py @@ -22,14 +22,14 @@ del absolute_import, print_function, unicode_literals import os import subprocess -import pyme +import gpg import support -support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP) +support.init_gpgme(gpg.constants.PROTOCOL_OpenPGP) subprocess.check_call([os.path.join(os.getenv('top_srcdir'), "tests", "start-stop-agent"), "--start"]) -with pyme.Context() as c: +with gpg.Context() as c: alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) diff --git a/lang/python/tests/support.py b/lang/python/tests/support.py index f1ffdc38..280ed063 100644 --- a/lang/python/tests/support.py +++ b/lang/python/tests/support.py @@ -20,7 +20,7 @@ del absolute_import, print_function, unicode_literals import sys import os -from pyme import core +from gpg import core # known keys alpha = "A0FF4590BB6122EDEF6E3C542D727CC768697734" diff --git a/lang/python/tests/t-callbacks.py b/lang/python/tests/t-callbacks.py index b3b43497..ebe51fdf 100755 --- a/lang/python/tests/t-callbacks.py +++ b/lang/python/tests/t-callbacks.py @@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import os -from pyme import core, constants +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -87,7 +87,7 @@ Key-Type: RSA Key-Length: 1024 Name-Real: Joe Tester Name-Comment: with stupid passphrase -Name-Email: joe+pyme@example.org +Name-Email: joe+gpg@example.org Passphrase: Crypt0R0cks Expire-Date: 2020-12-31 diff --git a/lang/python/tests/t-data.py b/lang/python/tests/t-data.py index 4812a2e7..16b2a7b5 100755 --- a/lang/python/tests/t-data.py +++ b/lang/python/tests/t-data.py @@ -23,7 +23,7 @@ del absolute_import, print_function, unicode_literals import io import os import tempfile -from pyme import core +from gpg import core data = core.Data('Hello world!') assert data.read() == b'Hello world!' diff --git a/lang/python/tests/t-decrypt-verify.py b/lang/python/tests/t-decrypt-verify.py index a38a965b..aa5971b9 100755 --- a/lang/python/tests/t-decrypt-verify.py +++ b/lang/python/tests/t-decrypt-verify.py @@ -20,8 +20,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme -from pyme import core, constants, errors +import gpg +from gpg import core, constants, errors import support def check_verify_result(result, summary, fpr, status): @@ -55,7 +55,7 @@ check_verify_result(verify_result, errors.NO_ERROR) # Idiomatic interface. -with pyme.Context() as c: +with gpg.Context() as c: alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False) bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False) plaintext, _, verify_result = \ diff --git a/lang/python/tests/t-decrypt.py b/lang/python/tests/t-decrypt.py index 2d85bc2b..74df3427 100755 --- a/lang/python/tests/t-decrypt.py +++ b/lang/python/tests/t-decrypt.py @@ -20,8 +20,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -38,7 +38,7 @@ assert not result.unsupported_algorithm, \ support.print_data(sink) # Idiomatic interface. -with pyme.Context() as c: +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, \ diff --git a/lang/python/tests/t-edit.py b/lang/python/tests/t-edit.py index 18bcb94e..a3023e43 100755 --- a/lang/python/tests/t-edit.py +++ b/lang/python/tests/t-edit.py @@ -23,7 +23,7 @@ del absolute_import, print_function, unicode_literals import sys import os -from pyme import core, constants +from gpg import core, constants import support class KeyEditor(object): diff --git a/lang/python/tests/t-encrypt-large.py b/lang/python/tests/t-encrypt-large.py index b9cc3b57..25373d73 100755 --- a/lang/python/tests/t-encrypt-large.py +++ b/lang/python/tests/t-encrypt-large.py @@ -22,7 +22,7 @@ del absolute_import, print_function, unicode_literals import sys import random -from pyme import core, constants +from gpg import core, constants import support if len(sys.argv) == 2: diff --git a/lang/python/tests/t-encrypt-sign.py b/lang/python/tests/t-encrypt-sign.py index a453f796..a1197e51 100755 --- a/lang/python/tests/t-encrypt-sign.py +++ b/lang/python/tests/t-encrypt-sign.py @@ -21,8 +21,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import sys -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -76,7 +76,7 @@ for recipients in (keys, []): # Idiomatic interface. -with pyme.Context(armor=True) as c: +with gpg.Context(armor=True) as c: message = "Hallo Leute\n".encode() ciphertext, _, sig_result = c.encrypt(message, recipients=keys, @@ -91,7 +91,7 @@ with pyme.Context(armor=True) as c: c.signers = [c.get_key(support.encrypt_only, True)] try: c.encrypt(message, recipients=keys, always_trust=True) - except pyme.errors.InvalidSigners as e: + except gpg.errors.InvalidSigners as e: assert len(e.signers) == 1 assert support.encrypt_only.endswith(e.signers[0].fpr) else: diff --git a/lang/python/tests/t-encrypt-sym.py b/lang/python/tests/t-encrypt-sym.py index d5771845..588e7a51 100755 --- a/lang/python/tests/t-encrypt-sym.py +++ b/lang/python/tests/t-encrypt-sym.py @@ -21,8 +21,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import os -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -68,7 +68,7 @@ for passphrase in ("abc", b"abc"): # Idiomatic interface. for passphrase in ("abc", b"abc"): - with pyme.Context(armor=True) as c: + with gpg.Context(armor=True) as c: # Check that the passphrase callback is not altered. def f(*args): assert False diff --git a/lang/python/tests/t-encrypt.py b/lang/python/tests/t-encrypt.py index 65e7d248..9ea2ce14 100755 --- a/lang/python/tests/t-encrypt.py +++ b/lang/python/tests/t-encrypt.py @@ -20,8 +20,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -42,7 +42,7 @@ assert not result.invalid_recipients, \ support.print_data(sink) # Idiomatic interface. -with pyme.Context(armor=True) as c: +with gpg.Context(armor=True) as c: ciphertext, _, _ = c.encrypt("Hallo Leute\n".encode(), recipients=keys, sign=False, @@ -58,7 +58,7 @@ with pyme.Context(armor=True) as c: c.encrypt("Hallo Leute\n".encode(), recipients=[c.get_key(support.sign_only, False)], sign=False, always_trust=True) - except pyme.errors.InvalidRecipients as e: + except gpg.errors.InvalidRecipients as e: assert len(e.recipients) == 1 assert support.sign_only.endswith(e.recipients[0].fpr) else: diff --git a/lang/python/tests/t-export.py b/lang/python/tests/t-export.py index db36b989..d96e04d8 100755 --- a/lang/python/tests/t-export.py +++ b/lang/python/tests/t-export.py @@ -20,7 +20,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -from pyme import core, constants +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) diff --git a/lang/python/tests/t-file-name.py b/lang/python/tests/t-file-name.py index e93b1200..6038fb5c 100755 --- a/lang/python/tests/t-file-name.py +++ b/lang/python/tests/t-file-name.py @@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import os -from pyme import core, constants +from gpg import core, constants import support testname = "abcde12345" diff --git a/lang/python/tests/t-idiomatic.py b/lang/python/tests/t-idiomatic.py index f0632064..4df8742c 100755 --- a/lang/python/tests/t-idiomatic.py +++ b/lang/python/tests/t-idiomatic.py @@ -24,13 +24,13 @@ import sys import io import os import tempfile -import pyme +import gpg import support -support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP) +support.init_gpgme(gpg.constants.PROTOCOL_OpenPGP) # Both Context and Data can be used as context manager: -with pyme.Context() as c, pyme.Data() as d: +with gpg.Context() as c, gpg.Data() as d: c.get_engine_info() d.write(b"Halloechen") leak_c = c @@ -39,17 +39,17 @@ assert leak_c.wrapped == None assert leak_d.wrapped == None def sign_and_verify(source, signed, sink): - with pyme.Context() as c: - c.op_sign(source, signed, pyme.constants.SIG_MODE_NORMAL) + 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 == (pyme.constants.SIGSUM_VALID | - pyme.constants.SIGSUM_GREEN) - assert pyme.errors.GPGMEError(sig.status).getcode() == pyme.errors.NO_ERROR + 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" @@ -80,5 +80,5 @@ if sys.version_info[0] == 3: # 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, pyme.Data() as sink: + 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 0b50d027..1d15b96b 100755 --- a/lang/python/tests/t-import.py +++ b/lang/python/tests/t-import.py @@ -20,7 +20,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -from pyme import core, constants +from gpg import core, constants import support def check_result(result, fpr, secret): diff --git a/lang/python/tests/t-keylist.py b/lang/python/tests/t-keylist.py index f7f6674e..8dd12ae6 100755 --- a/lang/python/tests/t-keylist.py +++ b/lang/python/tests/t-keylist.py @@ -20,8 +20,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) @@ -248,7 +248,7 @@ for i, key in enumerate(c.keylist()): # check get_key() -with pyme.Context() as c: +with gpg.Context() as c: c.get_key(support.alpha) c.get_key(support.alpha, secret=True) @@ -263,7 +263,7 @@ with pyme.Context() as c: # Legacy error try: c.get_key(support.no_such_key) - except pyme.errors.GPGMEError: + 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 172c7d0c..ad22ae3f 100755 --- a/lang/python/tests/t-protocol-assuan.py +++ b/lang/python/tests/t-protocol-assuan.py @@ -20,17 +20,17 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme +import gpg -with pyme.Context(protocol=pyme.constants.PROTOCOL_ASSUAN) as c: +with gpg.Context(protocol=gpg.constants.PROTOCOL_ASSUAN) as c: # Do nothing. c.assuan_transact('nop') c.assuan_transact('NOP') c.assuan_transact(['NOP']) err = c.assuan_transact('idontexist') - assert err.getsource() == pyme.errors.SOURCE_GPGAGENT - assert err.getcode() == pyme.errors.ASS_UNKNOWN_CMD + 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']) diff --git a/lang/python/tests/t-sig-notation.py b/lang/python/tests/t-sig-notation.py index eb5b111c..a30a7f45 100755 --- a/lang/python/tests/t-sig-notation.py +++ b/lang/python/tests/t-sig-notation.py @@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import os -from pyme import core, constants +from gpg import core, constants import support expected_notations = { diff --git a/lang/python/tests/t-sign.py b/lang/python/tests/t-sign.py index b0e211a1..f07f6efd 100755 --- a/lang/python/tests/t-sign.py +++ b/lang/python/tests/t-sign.py @@ -21,8 +21,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import os -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support def fail(msg): @@ -90,23 +90,23 @@ check_result(result, constants.SIG_MODE_CLEAR) support.print_data(sink) # Idiomatic interface. -with pyme.Context(armor=True, textmode=True) as c: +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=pyme.constants.SIG_MODE_DETACH) + 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=pyme.constants.SIG_MODE_CLEAR) + 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 pyme.Context() as c: +with gpg.Context() as c: message = "Hallo Leute\n".encode() c.signers = [c.get_key(support.sign_only, True)] @@ -115,7 +115,7 @@ with pyme.Context() as c: c.signers = [c.get_key(support.encrypt_only, True)] try: c.sign(message) - except pyme.errors.InvalidSigners as e: + except gpg.errors.InvalidSigners as e: assert len(e.signers) == 1 assert support.encrypt_only.endswith(e.signers[0].fpr) else: diff --git a/lang/python/tests/t-signers.py b/lang/python/tests/t-signers.py index 11403aff..6afe8f64 100755 --- a/lang/python/tests/t-signers.py +++ b/lang/python/tests/t-signers.py @@ -20,8 +20,8 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -import pyme -from pyme import core, constants +import gpg +from gpg import core, constants import support def fail(msg): @@ -81,7 +81,7 @@ for mode in (constants.SIG_MODE_NORMAL, constants.SIG_MODE_DETACH, support.print_data(sink) # Idiomatic interface. -with pyme.Context(armor=True, textmode=True, signers=keys) as c: +with gpg.Context(armor=True, textmode=True, signers=keys) as c: message = "Hallo Leute\n".encode() signed, result = c.sign(message) check_result(result, constants.SIG_MODE_NORMAL) diff --git a/lang/python/tests/t-trustlist.py b/lang/python/tests/t-trustlist.py index 4253bd7e..43424c3c 100755 --- a/lang/python/tests/t-trustlist.py +++ b/lang/python/tests/t-trustlist.py @@ -20,7 +20,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals -from pyme import core, constants +from gpg import core, constants import support support.init_gpgme(constants.PROTOCOL_OpenPGP) diff --git a/lang/python/tests/t-verify.py b/lang/python/tests/t-verify.py index 39f6176d..830c1788 100755 --- a/lang/python/tests/t-verify.py +++ b/lang/python/tests/t-verify.py @@ -22,8 +22,8 @@ del absolute_import, print_function, unicode_literals import sys import os -import pyme -from pyme import core, constants, errors +import gpg +from gpg import core, constants, errors import support test_text1 = b"Just GNU it!\n" @@ -145,7 +145,7 @@ else: # Idiomatic interface. -with pyme.Context(armor=True) as c: +with gpg.Context(armor=True) as c: # Checking a valid message. _, result = c.verify(test_text1, test_sig1) check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN, diff --git a/lang/python/tests/t-wait.py b/lang/python/tests/t-wait.py index b7d9a34b..96461f3e 100755 --- a/lang/python/tests/t-wait.py +++ b/lang/python/tests/t-wait.py @@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, unicode_literals del absolute_import, print_function, unicode_literals import time -from pyme import core, constants, errors +from gpg import core, constants, errors import support support.init_gpgme(constants.PROTOCOL_OpenPGP) diff --git a/lang/python/tests/t-wrapper.py b/lang/python/tests/t-wrapper.py index d260264f..3ffd3e80 100755 --- a/lang/python/tests/t-wrapper.py +++ b/lang/python/tests/t-wrapper.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . -from pyme import core +from gpg import core d0 = core.Data() d0.seek # trigger on-demand-wrapping -- cgit v1.2.3