From f9e57316aed7ba3bdc48859ac80a78c20d9c44e8 Mon Sep 17 00:00:00 2001 From: Ben Finney Date: Sun, 16 Oct 2016 15:41:16 +1100 Subject: [PATCH] Add helper functions to describe GPGME Signature objects. --- dput/crypto.py | 77 +++++++++++++++++++++++++++++ test/test_crypto.py | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 dput/crypto.py create mode 100644 test/test_crypto.py diff --git a/dput/crypto.py b/dput/crypto.py new file mode 100644 index 0000000..7a0dc39 --- /dev/null +++ b/dput/crypto.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8; -*- +# +# dput/crypto.py +# Part of ‘dput’, a Debian package upload toolkit. +# +# Copyright © 2016 Ben Finney +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +""" Cryptographic and hashing functionality. """ + +from __future__ import (absolute_import, unicode_literals) + +import gpgme + + +def characterise_signature(signature): + """ Make a phrase characterising a GnuPG signature. + + :param signature: A `gpgme.Signature` instance. + :return: A simple text phrase characterising the `signature`. + + * If the signature is valid, the result is "valid". + * If the signature is not valid, but is good, the result is + "good". + * If the signature is not good, the result is "bad". + + """ + text = "UNKNOWN" + if (signature.summary & gpgme.SIGSUM_VALID): + text = "valid" + elif (signature.summary & gpgme.SIGSUM_RED): + text = "bad" + elif (signature.summary & gpgme.SIGSUM_GREEN): + text = "good" + + return text + + +def describe_signature(signature): + """ Make a message describing a GnuPG signature. + + :param signature: A `gpgme.Signature` instance. + :return: A text description of the salient points of the + `signature`. + + The description includes the signature's character (whether it + is valid, good, or bad); and the key ID used to create the + signature. + + """ + character = characterise_signature(signature) + fpr_length = 16 + text = "{character} signature from {fpr}".format( + character=character.title(), + fpr=signature.fpr[-fpr_length:]) + + return text + + +# Local variables: +# coding: utf-8 +# mode: python +# End: +# vim: fileencoding=utf-8 filetype=python : diff --git a/test/test_crypto.py b/test/test_crypto.py new file mode 100644 index 0000000..22cfff9 --- /dev/null +++ b/test/test_crypto.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8; -*- +# +# test/test_crypto.py +# Part of ‘dput’, a Debian package upload toolkit. +# +# Copyright © 2015–2016 Ben Finney +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 3 of that license or any later version. +# No warranty expressed or implied. See the file ‘LICENSE.GPL-3’ for details. + +""" Unit tests for ‘crypto’ module. """ + +from __future__ import (absolute_import, unicode_literals) + +import functools +import operator +import os +import os.path +import sys + +import gpgme +import testscenarios +import testtools + +__package__ = str("test") +__import__(__package__) +sys.path.insert(1, os.path.dirname(os.path.dirname(__file__))) +import dput.crypto + +from .helper import ( + mock, + ) + + +def make_gpgme_signature_scenarios(): + """ Make a collection of scenarios for `gpgme.Signature` instances. """ + + scenarios = [ + ('signature-good validity-unknown', { + 'signature': mock.MagicMock( + gpgme.Signature, + fpr="BADBEEF2FACEDCADF00DBEEFDECAFBAD", + status=gpgme.ERR_NO_ERROR, + summary=functools.reduce( + operator.ior, [gpgme.SIGSUM_GREEN]), + validity=gpgme.VALIDITY_UNKNOWN), + 'expected_character': "good", + 'expected_description': ( + "Good signature from F00DBEEFDECAFBAD"), + }), + ('signature-good validity-never', { + 'signature': mock.MagicMock( + gpgme.Signature, + fpr="BADBEEF2FACEDCADF00DBEEFDECAFBAD", + status=gpgme.ERR_NO_ERROR, + summary=functools.reduce( + operator.ior, [gpgme.SIGSUM_GREEN]), + validity=gpgme.VALIDITY_NEVER), + 'expected_character': "good", + 'expected_description': ( + "Good signature from F00DBEEFDECAFBAD"), + }), + ('signature-good validity-full key-expired', { + 'signature': mock.MagicMock( + gpgme.Signature, + fpr="BADBEEF2FACEDCADF00DBEEFDECAFBAD", + status=gpgme.ERR_NO_ERROR, + summary=functools.reduce(operator.ior, [ + gpgme.SIGSUM_GREEN, gpgme.SIGSUM_KEY_EXPIRED]), + validity=gpgme.VALIDITY_FULL), + 'expected_character': "good", + 'expected_description': ( + "Good signature from F00DBEEFDECAFBAD"), + }), + ('signature-good validity-full', { + 'signature': mock.MagicMock( + gpgme.Signature, + fpr="BADBEEF2FACEDCADF00DBEEFDECAFBAD", + status=gpgme.ERR_NO_ERROR, + summary=functools.reduce(operator.ior, [ + gpgme.SIGSUM_VALID, gpgme.SIGSUM_GREEN]), + validity=gpgme.VALIDITY_FULL), + 'expected_character': "valid", + 'expected_description': ( + "Valid signature from F00DBEEFDECAFBAD"), + }), + ('signature-bad', { + 'signature': mock.MagicMock( + gpgme.Signature, + fpr="BADBEEF2FACEDCADF00DBEEFDECAFBAD", + status=gpgme.ERR_BAD_SIGNATURE, + summary=functools.reduce( + operator.ior, [gpgme.SIGSUM_RED]), + validity=gpgme.VALIDITY_FULL), + 'expected_character': "bad", + 'expected_description': ( + "Bad signature from F00DBEEFDECAFBAD"), + }), + ] + + return scenarios + + +class characterise_signature_TestCase( + testscenarios.WithScenarios, + testtools.TestCase): + """ Test cases for function `characterise_signature`. """ + + scenarios = make_gpgme_signature_scenarios() + + def test_returns_expected_character(self): + """ Should return expected character for signature. """ + result = dput.crypto.characterise_signature(self.signature) + self.assertEqual(result, self.expected_character) + + +class describe_signature_TestCase( + testscenarios.WithScenarios, + testtools.TestCase): + """ Test cases for function `describe_signature`. """ + + scenarios = make_gpgme_signature_scenarios() + + def test_returns_expected_character(self): + """ Should return expected character for signature. """ + result = dput.crypto.describe_signature(self.signature) + self.assertEqual(result, self.expected_description) + + +# Local variables: +# coding: utf-8 +# mode: python +# End: +# vim: fileencoding=utf-8 filetype=python : -- 2.11.4.GIT