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