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