/brz/remove-bazaar

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