/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6609.1.1 by Vincent Ladeuil
Fix the failing gpg test on wily.
1
# Copyright (C) 2005, 2006, 2007, 2009, 2011, 2012, 2013, 2016 Canonical Ltd
1442.1.57 by Robert Collins
check that we get the right command line from the default gpg strategy.
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1442.1.57 by Robert Collins
check that we get the right command line from the default gpg strategy.
17
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
18
"""GPG signing and checking logic."""
19
6379.6.3 by Jelmer Vernooij
Use absolute_import.
20
from __future__ import absolute_import
21
1996.3.1 by John Arbash Meinel
Demandloading builtins.py drops our load time from 350ms to 291ms
22
import os
23
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
24
from breezy.lazy_import import lazy_import
1996.3.1 by John Arbash Meinel
Demandloading builtins.py drops our load time from 350ms to 291ms
25
lazy_import(globals(), """
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
26
from breezy import (
6372.1.3 by Vincent Ladeuil
Fix gpg_signing_ket default values handling
27
    config,
1912.3.2 by John Arbash Meinel
Adding some logging, because on my machine TTY is not exported by default.
28
    trace,
1551.8.11 by Aaron Bentley
Clear terminal before signing
29
    ui,
1912.3.2 by John Arbash Meinel
Adding some logging, because on my machine TTY is not exported by default.
30
    )
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
31
from breezy.i18n import (
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
32
    gettext,
6092.2.3 by Jonathan Riddell
improve formatting
33
    ngettext,
34
    )
1996.3.1 by John Arbash Meinel
Demandloading builtins.py drops our load time from 350ms to 291ms
35
""")
1442.1.57 by Robert Collins
check that we get the right command line from the default gpg strategy.
36
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
37
from . import (
38
    errors,
39
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
40
from .sixish import (
6973.6.2 by Jelmer Vernooij
Fix more tests.
41
    text_type,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
42
    )
6491.1.4 by Jelmer Vernooij
Deprecate GPGStrategy.do_verifications.
43
7143.15.2 by Jelmer Vernooij
Run autopep8.
44
# verification results
5971.1.1 by Jonathan Riddell
add a verify command
45
SIGNATURE_VALID = 0
46
SIGNATURE_KEY_MISSING = 1
47
SIGNATURE_NOT_VALID = 2
48
SIGNATURE_NOT_SIGNED = 3
6043.3.1 by Jonathan Riddell
Report commits signed with expired keys in "verify-signatures".
49
SIGNATURE_EXPIRED = 4
5971.1.1 by Jonathan Riddell
add a verify command
50
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
51
MODE_NORMAL = 0
52
MODE_DETACH = 1
53
MODE_CLEAR = 2
54
5971.1.1 by Jonathan Riddell
add a verify command
55
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
56
class GpgNotInstalled(errors.DependencyNotPresent):
57
7195.4.2 by Jelmer Vernooij
Clarify error messages.
58
    _fmt = ('python-gpg is not installed, it is needed to create or '
59
            'verify signatures. %(error)s')
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
60
61
    def __init__(self, error):
62
        errors.DependencyNotPresent.__init__(self, 'gpg', error)
63
64
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
65
class SigningFailed(errors.BzrError):
66
67
    _fmt = 'Failed to GPG sign data: "%(error)s"'
68
69
    def __init__(self, error):
70
        errors.BzrError.__init__(self, error=error)
71
72
73
class SignatureVerificationFailed(errors.BzrError):
74
75
    _fmt = 'Failed to verify GPG signature data with error "%(error)s"'
76
77
    def __init__(self, error):
78
        errors.BzrError.__init__(self, error=error)
79
80
6491.1.3 by Jelmer Vernooij
Make 'bzr verify-signatures' show a progress bar.
81
def bulk_verify_signatures(repository, revids, strategy,
7143.15.2 by Jelmer Vernooij
Run autopep8.
82
                           process_events_callback=None):
6491.1.3 by Jelmer Vernooij
Make 'bzr verify-signatures' show a progress bar.
83
    """Do verifications on a set of revisions
84
85
    :param repository: repository object
86
    :param revids: list of revision ids to verify
87
    :param strategy: GPG strategy to use
88
    :param process_events_callback: method to call for GUI frontends that
89
        want to keep their UI refreshed
90
91
    :return: count dictionary of results of each type,
92
             result list for each revision,
93
             boolean True if all results are verified successfully
94
    """
95
    count = {SIGNATURE_VALID: 0,
96
             SIGNATURE_KEY_MISSING: 0,
97
             SIGNATURE_NOT_VALID: 0,
98
             SIGNATURE_NOT_SIGNED: 0,
99
             SIGNATURE_EXPIRED: 0}
100
    result = []
101
    all_verifiable = True
102
    total = len(revids)
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
103
    with ui.ui_factory.nested_progress_bar() as pb:
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
104
        for i, (rev_id, verification_result, uid) in enumerate(
105
                repository.verify_revision_signatures(
106
                    revids, strategy)):
6491.1.3 by Jelmer Vernooij
Make 'bzr verify-signatures' show a progress bar.
107
            pb.update("verifying signatures", i, total)
108
            result.append([rev_id, verification_result, uid])
109
            count[verification_result] += 1
110
            if verification_result != SIGNATURE_VALID:
111
                all_verifiable = False
112
            if process_events_callback is not None:
113
                process_events_callback()
114
    return (count, result, all_verifiable)
115
116
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
117
class DisabledGPGStrategy(object):
118
    """A GPG Strategy that makes everything fail."""
119
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
120
    @staticmethod
121
    def verify_signatures_available():
122
        return True
123
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
124
    def __init__(self, ignored):
125
        """Real strategies take a configuration."""
126
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
127
    def sign(self, content, mode):
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
128
        raise SigningFailed('Signing is disabled.')
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
129
6883.11.2 by Jelmer Vernooij
Change signature API.
130
    def verify(self, signed_data, signature=None):
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
131
        raise SignatureVerificationFailed('Signature verification is \
5971.1.33 by Jonathan Riddell
rename errors.VerifyFailed to errors.SignatureVerificationFailed
132
disabled.')
5971.1.6 by Jonathan Riddell
fix methods for dummy gpg strategies
133
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
134
    def set_acceptable_keys(self, command_line_input):
5971.1.14 by Jonathan Riddell
add test for set_acceptable_keys, accept non-trusted keys if specified as acceptable, import dummy key in tests so it works outside my machine
135
        pass
136
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
137
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
138
class LoopbackGPGStrategy(object):
5971.1.85 by Jonathan Riddell
use unicode strings for UI
139
    """A GPG Strategy that acts like 'cat' - data is just passed through.
5971.1.86 by Jonathan Riddell
doc string formatting
140
    Used in tests.
141
    """
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
142
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
143
    @staticmethod
144
    def verify_signatures_available():
145
        return True
146
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
147
    def __init__(self, ignored):
148
        """Real strategies take a configuration."""
149
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
150
    def sign(self, content, mode):
7143.15.2 by Jelmer Vernooij
Run autopep8.
151
        return (b"-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content
152
                + b"-----END PSEUDO-SIGNED CONTENT-----\n")
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
153
6883.11.2 by Jelmer Vernooij
Change signature API.
154
    def verify(self, signed_data, signature=None):
7143.15.2 by Jelmer Vernooij
Run autopep8.
155
        plain_text = signed_data.replace(
156
            b"-----BEGIN PSEUDO-SIGNED CONTENT-----\n", b"")
157
        plain_text = plain_text.replace(
158
            b"-----END PSEUDO-SIGNED CONTENT-----\n", b"")
6883.11.3 by Jelmer Vernooij
Fix tests.
159
        return SIGNATURE_VALID, None, plain_text
5971.1.5 by Jonathan Riddell
catch errors from gpgme, implement verify in dummy gpg strategies
160
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
161
    def set_acceptable_keys(self, command_line_input):
162
        if command_line_input is not None:
163
            patterns = command_line_input.split(",")
164
            self.acceptable_keys = []
165
            for pattern in patterns:
166
                if pattern == "unknown":
167
                    pass
168
                else:
169
                    self.acceptable_keys.append(pattern)
5971.1.14 by Jonathan Riddell
add test for set_acceptable_keys, accept non-trusted keys if specified as acceptable, import dummy key in tests so it works outside my machine
170
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
171
1912.3.1 by John Arbash Meinel
updating gpg.py to set GPG_TTY in the environment.
172
def _set_gpg_tty():
173
    tty = os.environ.get('TTY')
174
    if tty is not None:
175
        os.environ['GPG_TTY'] = tty
1912.3.2 by John Arbash Meinel
Adding some logging, because on my machine TTY is not exported by default.
176
        trace.mutter('setting GPG_TTY=%s', tty)
177
    else:
178
        # This is not quite worthy of a warning, because some people
179
        # don't need GPG_TTY to be set. But it is worthy of a big mark
6622.1.33 by Jelmer Vernooij
Fix more tests (all?)
180
        # in ~/.brz.log, so that people can debug it if it happens to them
1912.3.2 by John Arbash Meinel
Adding some logging, because on my machine TTY is not exported by default.
181
        trace.mutter('** Env var TTY empty, cannot set GPG_TTY.'
182
                     '  Is TTY exported?')
1912.3.1 by John Arbash Meinel
updating gpg.py to set GPG_TTY in the environment.
183
184
1442.1.57 by Robert Collins
check that we get the right command line from the default gpg strategy.
185
class GPGStrategy(object):
186
    """GPG Signing and checking facilities."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
187
5971.1.11 by Jonathan Riddell
add set_acceptable_keys() so user can specify which gpg keys can be used for verification
188
    acceptable_keys = None
189
6351.3.9 by Vincent Ladeuil
Move __init__ at the beginning of the class since that's the current idiom.
190
    def __init__(self, config_stack):
191
        self._config_stack = config_stack
192
        try:
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
193
            import gpg
194
            self.context = gpg.Context()
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
195
            self.context.armor = True
6883.11.6 by Jelmer Vernooij
Support tests on machines without gpg.
196
            self.context.signers = self._get_signing_keys()
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
197
        except ImportError:
7143.15.2 by Jelmer Vernooij
Run autopep8.
198
            pass  # can't use verify()
6351.3.9 by Vincent Ladeuil
Move __init__ at the beginning of the class since that's the current idiom.
199
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
200
    def _get_signing_keys(self):
201
        import gpg
202
        keyname = self._config_stack.get('gpg_signing_key')
7239.3.1 by Jelmer Vernooij
Support gpg_signing_key=default to indicate using the default GPG key.
203
        if keyname == 'default':
204
            # Leave things to gpg
205
            return []
206
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
207
        if keyname:
208
            try:
209
                return [self.context.get_key(keyname)]
210
            except gpg.errors.KeyNotFound:
211
                pass
212
7239.3.1 by Jelmer Vernooij
Support gpg_signing_key=default to indicate using the default GPG key.
213
        if keyname is None:
214
            # not setting gpg_signing_key at all means we should
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
215
            # use the user email address
7143.15.2 by Jelmer Vernooij
Run autopep8.
216
            keyname = config.extract_email_address(
217
                self._config_stack.get('email'))
7240.9.1 by Jelmer Vernooij
Fix GPG signature validation on Python 3.
218
        if keyname == 'default':
219
            return []
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
220
        possible_keys = self.context.keylist(keyname, secret=True)
221
        try:
6973.10.3 by Jelmer Vernooij
Port GPG to python3.
222
            return [next(possible_keys)]
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
223
        except StopIteration:
224
            return []
225
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
226
    @staticmethod
227
    def verify_signatures_available():
5971.1.82 by Jonathan Riddell
method doc
228
        """
5971.1.86 by Jonathan Riddell
doc string formatting
229
        check if this strategy can verify signatures
230
5971.1.82 by Jonathan Riddell
method doc
231
        :return: boolean if this strategy can verify signatures
232
        """
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
233
        try:
7143.11.1 by Jelmer Vernooij
Remove some unused imports.
234
            import gpg  # noqa: F401
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
235
            return True
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
236
        except ImportError:
5971.1.60 by Jonathan Riddell
move checking for gpgme availability into gpg.py
237
            return False
238
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
239
    def sign(self, content, mode):
7195.4.1 by Jelmer Vernooij
Raise GpgNotInstalled.
240
        try:
241
            import gpg
242
        except ImportError as error:
7195.4.2 by Jelmer Vernooij
Clarify error messages.
243
            raise GpgNotInstalled(
244
                'Set create_signatures=no to disable creating signatures.')
7195.4.1 by Jelmer Vernooij
Raise GpgNotInstalled.
245
6973.6.2 by Jelmer Vernooij
Fix more tests.
246
        if isinstance(content, text_type):
2273.1.1 by John Arbash Meinel
``GPGStrategy.sign()`` will now raise ``BzrBadParameterUnicode`` if
247
            raise errors.BzrBadParameterUnicode('content')
1963.1.8 by John Arbash Meinel
Don't use preexec_fn on win32
248
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
249
        plain_text = gpg.Data(content)
1442.1.58 by Robert Collins
gpg signing of content
250
        try:
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
251
            output, result = self.context.sign(
6883.11.1 by Jelmer Vernooij
Add support for a mode argument to GPGStrategy.sign.
252
                plain_text, mode={
253
                    MODE_DETACH: gpg.constants.sig.mode.DETACH,
254
                    MODE_CLEAR: gpg.constants.sig.mode.CLEAR,
255
                    MODE_NORMAL: gpg.constants.sig.mode.NORMAL,
256
                    }[mode])
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
257
        except gpg.errors.GPGMEError as error:
258
            raise SigningFailed(str(error))
259
260
        return output
5971.1.1 by Jonathan Riddell
add a verify command
261
6883.11.2 by Jelmer Vernooij
Change signature API.
262
    def verify(self, signed_data, signature=None):
5971.1.7 by Jonathan Riddell
add method docs
263
        """Check content has a valid signature.
6491.1.1 by Jelmer Vernooij
Various cleanups related to GPG.
264
6883.11.2 by Jelmer Vernooij
Change signature API.
265
        :param signed_data; Signed data
266
        :param signature: optional signature (if detached)
6491.1.1 by Jelmer Vernooij
Various cleanups related to GPG.
267
6883.11.2 by Jelmer Vernooij
Change signature API.
268
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid, plain text
5971.1.7 by Jonathan Riddell
add method docs
269
        """
5971.1.4 by Jonathan Riddell
tidy up repository and gpg.py
270
        try:
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
271
            import gpg
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
272
        except ImportError as error:
7195.4.2 by Jelmer Vernooij
Clarify error messages.
273
            raise GpgNotInstalled(
274
                'Set check_signatures=ignore to disable verifying signatures.')
5971.1.4 by Jonathan Riddell
tidy up repository and gpg.py
275
6883.11.2 by Jelmer Vernooij
Change signature API.
276
        signed_data = gpg.Data(signed_data)
277
        if signature:
278
            signature = gpg.Data(signature)
5971.1.5 by Jonathan Riddell
catch errors from gpgme, implement verify in dummy gpg strategies
279
        try:
6883.11.2 by Jelmer Vernooij
Change signature API.
280
            plain_output, result = self.context.verify(signed_data, signature)
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
281
        except gpg.errors.BadSignatures as error:
282
            fingerprint = error.result.signatures[0].fpr
283
            if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED:
7143.15.2 by Jelmer Vernooij
Run autopep8.
284
                expires = self.context.get_key(
285
                    error.result.signatures[0].fpr).subkeys[0].expires
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
286
                if expires > error.result.signatures[0].timestamp:
287
                    # The expired key was not expired at time of signing.
288
                    # test_verify_expired_but_valid()
6883.11.2 by Jelmer Vernooij
Change signature API.
289
                    return SIGNATURE_EXPIRED, fingerprint[-8:], None
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
290
                else:
291
                    # I can't work out how to create a test where the signature
292
                    # was expired at the time of signing.
6883.11.2 by Jelmer Vernooij
Change signature API.
293
                    return SIGNATURE_NOT_VALID, None, None
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
294
295
            # GPG does not know this key.
296
            # test_verify_unknown_key()
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
297
            if (error.result.signatures[0].summary &
298
                    gpg.constants.SIGSUM_KEY_MISSING):
6883.11.2 by Jelmer Vernooij
Change signature API.
299
                return SIGNATURE_KEY_MISSING, fingerprint[-8:], None
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
300
6883.11.2 by Jelmer Vernooij
Change signature API.
301
            return SIGNATURE_NOT_VALID, None, None
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
302
        except gpg.errors.GPGMEError as error:
6883.11.2 by Jelmer Vernooij
Change signature API.
303
            raise SignatureVerificationFailed(error)
5971.1.1 by Jonathan Riddell
add a verify command
304
6883.11.3 by Jelmer Vernooij
Fix tests.
305
        # No result if input is invalid.
306
        # test_verify_invalid()
307
        if len(result.signatures) == 0:
308
            return SIGNATURE_NOT_VALID, None, plain_output
309
6372.1.1 by Vincent Ladeuil
Remove spurious spaces.
310
        # User has specified a list of acceptable keys, check our result is in
311
        # it.  test_verify_unacceptable_key()
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
312
        fingerprint = result.signatures[0].fpr
5971.1.13 by Jonathan Riddell
return missing if not in acceptable keys
313
        if self.acceptable_keys is not None:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
314
            if fingerprint not in self.acceptable_keys:
6883.11.2 by Jelmer Vernooij
Change signature API.
315
                return SIGNATURE_KEY_MISSING, fingerprint[-8:], plain_output
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
316
        # Yay gpg set the valid bit.
6043.2.15 by Jonathan Riddell
turn comments into sentences
317
        # Can't write a test for this one as you can't set a key to be
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
318
        # trusted using gpg.
319
        if result.signatures[0].summary & gpg.constants.SIGSUM_VALID:
5971.1.61 by Jonathan Riddell
make gpgme context global to class
320
            key = self.context.get_key(fingerprint)
5971.1.17 by Jonathan Riddell
add verbose option
321
            name = key.uids[0].name
7240.9.1 by Jelmer Vernooij
Fix GPG signature validation on Python 3.
322
            if isinstance(name, bytes):
323
                name = name.decode('utf-8')
5971.1.18 by Jonathan Riddell
add email to verbose output
324
            email = key.uids[0].email
7240.9.1 by Jelmer Vernooij
Fix GPG signature validation on Python 3.
325
            if isinstance(email, bytes):
326
                email = email.decode('utf-8')
327
            return (SIGNATURE_VALID, name + u" <" + email + u">", plain_output)
6043.2.15 by Jonathan Riddell
turn comments into sentences
328
        # Sigsum_red indicates a problem, unfortunatly I have not been able
329
        # to write any tests which actually set this.
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
330
        if result.signatures[0].summary & gpg.constants.SIGSUM_RED:
6883.11.2 by Jelmer Vernooij
Change signature API.
331
            return SIGNATURE_NOT_VALID, None, plain_output
6372.1.1 by Vincent Ladeuil
Remove spurious spaces.
332
        # Summary isn't set if sig is valid but key is untrusted but if user
333
        # has explicity set the key as acceptable we can validate it.
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
334
        if (result.signatures[0].summary == 0 and
335
                self.acceptable_keys is not None):
5971.1.14 by Jonathan Riddell
add test for set_acceptable_keys, accept non-trusted keys if specified as acceptable, import dummy key in tests so it works outside my machine
336
            if fingerprint in self.acceptable_keys:
6043.2.15 by Jonathan Riddell
turn comments into sentences
337
                # test_verify_untrusted_but_accepted()
6883.11.2 by Jelmer Vernooij
Change signature API.
338
                return SIGNATURE_VALID, None, plain_output
6043.2.15 by Jonathan Riddell
turn comments into sentences
339
        # test_verify_valid_but_untrusted()
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
340
        if result.signatures[0].summary == 0 and self.acceptable_keys is None:
6883.11.2 by Jelmer Vernooij
Change signature API.
341
            return SIGNATURE_NOT_VALID, None, plain_output
6043.2.15 by Jonathan Riddell
turn comments into sentences
342
        # Other error types such as revoked keys should (I think) be caught by
343
        # SIGSUM_RED so anything else means something is buggy.
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
344
        raise SignatureVerificationFailed(
6609.1.1 by Vincent Ladeuil
Fix the failing gpg test on wily.
345
            "Unknown GnuPG key verification result")
5971.1.11 by Jonathan Riddell
add set_acceptable_keys() so user can specify which gpg keys can be used for verification
346
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
347
    def set_acceptable_keys(self, command_line_input):
6351.3.2 by Jelmer Vernooij
Convert some gpg options to config stacks.
348
        """Set the acceptable keys for verifying with this GPGStrategy.
6491.1.1 by Jelmer Vernooij
Various cleanups related to GPG.
349
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
350
        :param command_line_input: comma separated list of patterns from
351
                                command line
352
        :return: nothing
353
        """
6589.3.1 by Vincent Ladeuil
Fix command line override handling for acceptable_keys
354
        patterns = None
6351.3.2 by Jelmer Vernooij
Convert some gpg options to config stacks.
355
        acceptable_keys_config = self._config_stack.get('acceptable_keys')
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
356
        if acceptable_keys_config is not None:
6589.3.1 by Vincent Ladeuil
Fix command line override handling for acceptable_keys
357
            patterns = acceptable_keys_config
7143.15.2 by Jelmer Vernooij
Run autopep8.
358
        if command_line_input is not None:  # command line overrides config
6589.3.1 by Vincent Ladeuil
Fix command line override handling for acceptable_keys
359
            patterns = command_line_input.split(',')
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
360
6589.3.1 by Vincent Ladeuil
Fix command line override handling for acceptable_keys
361
        if patterns:
5971.1.69 by Jonathan Riddell
move some code from cmd_verify to gpg.set_acceptable_keys
362
            self.acceptable_keys = []
363
            for pattern in patterns:
364
                result = self.context.keylist(pattern)
365
                found_key = False
366
                for key in result:
367
                    found_key = True
368
                    self.acceptable_keys.append(key.subkeys[0].fpr)
369
                    trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
370
                if not found_key:
6092.2.1 by Jonathan Riddell
Use gettext.NullTranslations in i18n to allow use of i18n even when translations are not turned on
371
                    trace.note(gettext(
7143.15.2 by Jelmer Vernooij
Run autopep8.
372
                        "No GnuPG key results for pattern: {0}"
373
                        ).format(pattern))
5971.1.70 by Jonathan Riddell
move code which does verifications of revisions from cmd_verify_signatures to gpg.do_verifications
374
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
375
376
def valid_commits_message(count):
377
    """returns message for number of commits"""
378
    return gettext(u"{0} commits with valid signatures").format(
7143.15.2 by Jelmer Vernooij
Run autopep8.
379
        count[SIGNATURE_VALID])
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
380
381
382
def unknown_key_message(count):
383
    """returns message for number of commits"""
384
    return ngettext(u"{0} commit with unknown key",
385
                    u"{0} commits with unknown keys",
386
                    count[SIGNATURE_KEY_MISSING]).format(
7143.15.2 by Jelmer Vernooij
Run autopep8.
387
        count[SIGNATURE_KEY_MISSING])
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
388
389
390
def commit_not_valid_message(count):
391
    """returns message for number of commits"""
392
    return ngettext(u"{0} commit not valid",
393
                    u"{0} commits not valid",
394
                    count[SIGNATURE_NOT_VALID]).format(
7143.15.2 by Jelmer Vernooij
Run autopep8.
395
        count[SIGNATURE_NOT_VALID])
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
396
397
398
def commit_not_signed_message(count):
399
    """returns message for number of commits"""
400
    return ngettext(u"{0} commit not signed",
401
                    u"{0} commits not signed",
402
                    count[SIGNATURE_NOT_SIGNED]).format(
7143.15.2 by Jelmer Vernooij
Run autopep8.
403
        count[SIGNATURE_NOT_SIGNED])
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
404
405
406
def expired_commit_message(count):
407
    """returns message for number of commits"""
408
    return ngettext(u"{0} commit with key now expired",
409
                    u"{0} commits with key now expired",
410
                    count[SIGNATURE_EXPIRED]).format(
7143.15.2 by Jelmer Vernooij
Run autopep8.
411
        count[SIGNATURE_EXPIRED])
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
412
413
414
def verbose_expired_key_message(result, repo):
415
    """takes a verify result and returns list of expired key info"""
416
    signers = {}
417
    fingerprint_to_authors = {}
418
    for rev_id, validity, fingerprint in result:
419
        if validity == SIGNATURE_EXPIRED:
420
            revision = repo.get_revision(rev_id)
421
            authors = ', '.join(revision.get_apparent_authors())
422
            signers.setdefault(fingerprint, 0)
423
            signers[fingerprint] += 1
424
            fingerprint_to_authors[fingerprint] = authors
425
    result = []
426
    for fingerprint, number in signers.items():
427
        result.append(
428
            ngettext(u"{0} commit by author {1} with key {2} now expired",
429
                     u"{0} commits by author {1} with key {2} now expired",
430
                     number).format(
431
                number, fingerprint_to_authors[fingerprint], fingerprint))
432
    return result
433
434
435
def verbose_valid_message(result):
436
    """takes a verify result and returns list of signed commits strings"""
437
    signers = {}
438
    for rev_id, validity, uid in result:
439
        if validity == SIGNATURE_VALID:
440
            signers.setdefault(uid, 0)
441
            signers[uid] += 1
442
    result = []
443
    for uid, number in signers.items():
7143.15.2 by Jelmer Vernooij
Run autopep8.
444
        result.append(ngettext(u"{0} signed {1} commit",
445
                               u"{0} signed {1} commits",
446
                               number).format(uid, number))
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
447
    return result
448
449
450
def verbose_not_valid_message(result, repo):
451
    """takes a verify result and returns list of not valid commit info"""
452
    signers = {}
453
    for rev_id, validity, empty in result:
454
        if validity == SIGNATURE_NOT_VALID:
455
            revision = repo.get_revision(rev_id)
456
            authors = ', '.join(revision.get_apparent_authors())
457
            signers.setdefault(authors, 0)
458
            signers[authors] += 1
459
    result = []
460
    for authors, number in signers.items():
461
        result.append(ngettext(u"{0} commit by author {1}",
462
                               u"{0} commits by author {1}",
463
                               number).format(number, authors))
464
    return result
465
466
467
def verbose_not_signed_message(result, repo):
468
    """takes a verify result and returns list of not signed commit info"""
469
    signers = {}
470
    for rev_id, validity, empty in result:
471
        if validity == SIGNATURE_NOT_SIGNED:
472
            revision = repo.get_revision(rev_id)
473
            authors = ', '.join(revision.get_apparent_authors())
474
            signers.setdefault(authors, 0)
475
            signers[authors] += 1
476
    result = []
477
    for authors, number in signers.items():
478
        result.append(ngettext(u"{0} commit by author {1}",
479
                               u"{0} commits by author {1}",
480
                               number).format(number, authors))
481
    return result
482
483
484
def verbose_missing_key_message(result):
485
    """takes a verify result and returns list of missing key info"""
486
    signers = {}
487
    for rev_id, validity, fingerprint in result:
488
        if validity == SIGNATURE_KEY_MISSING:
489
            signers.setdefault(fingerprint, 0)
490
            signers[fingerprint] += 1
491
    result = []
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
492
    for fingerprint, number in list(signers.items()):
6491.1.5 by Jelmer Vernooij
Add Repository.verify_revision_signatures.
493
        result.append(ngettext(u"Unknown key {0} signed {1} commit",
494
                               u"Unknown key {0} signed {1} commits",
495
                               number).format(fingerprint, number))
496
    return result