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