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