~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/gpg.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-06 22:44:57 UTC
  • mfrom: (6436 +trunk)
  • mto: (6437.3.11 2.5)
  • mto: This revision was merged to the branch mainline in revision 6444.
  • Revision ID: jelmer@samba.org-20120106224457-re0pcy0fz31xob77
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""GPG signing and checking logic."""
19
19
 
 
20
from __future__ import absolute_import
 
21
 
20
22
import os
21
23
import sys
22
24
from StringIO import StringIO
27
29
import subprocess
28
30
 
29
31
from bzrlib import (
 
32
    config,
30
33
    errors,
31
34
    trace,
32
35
    ui,
114
117
 
115
118
    def valid_commits_message(self, count):
116
119
        return gettext(u"{0} commits with valid signatures").format(
117
 
                                        count[SIGNATURE_VALID])            
 
120
                                        count[SIGNATURE_VALID])
118
121
 
119
122
    def unknown_key_message(self, count):
120
123
        return ngettext(u"{0} commit with unknown key",
159
162
 
160
163
    acceptable_keys = None
161
164
 
 
165
    def __init__(self, config_stack):
 
166
        self._config_stack = config_stack
 
167
        try:
 
168
            import gpgme
 
169
            self.context = gpgme.Context()
 
170
        except ImportError, error:
 
171
            pass # can't use verify()
 
172
 
162
173
    @staticmethod
163
174
    def verify_signatures_available():
164
175
        """
173
184
            return False
174
185
 
175
186
    def _command_line(self):
176
 
        
177
 
        return [self._config.gpg_signing_command(), '--clearsign', '-u',
178
 
                                                self._config.gpg_signing_key()]
179
 
 
180
 
    def __init__(self, config):
181
 
        self._config = config
182
 
        try:
183
 
            import gpgme
184
 
            self.context = gpgme.Context()
185
 
        except ImportError, error:
186
 
            pass # can't use verify()
 
187
        key = self._config_stack.get('gpg_signing_key')
 
188
        if key is None or key == 'default':
 
189
            # 'default' or not setting gpg_signing_key at all means we should
 
190
            # use the user email address
 
191
            key = config.extract_email_address(self._config_stack.get('email'))
 
192
        return [self._config_stack.get('gpg_signing_command'), '--clearsign',
 
193
                '-u', key]
187
194
 
188
195
    def sign(self, content):
189
196
        if isinstance(content, unicode):
236
243
 
237
244
        signature = StringIO(content)
238
245
        plain_output = StringIO()
239
 
        
240
246
        try:
241
247
            result = self.context.verify(signature, None, plain_output)
242
248
        except gpgme.GpgmeError,error:
246
252
        # test_verify_invalid()
247
253
        if len(result) == 0:
248
254
            return SIGNATURE_NOT_VALID, None
249
 
        # User has specified a list of acceptable keys, check our result is in it.
250
 
        # test_verify_unacceptable_key()
 
255
        # User has specified a list of acceptable keys, check our result is in
 
256
        # it.  test_verify_unacceptable_key()
251
257
        fingerprint = result[0].fpr
252
258
        if self.acceptable_keys is not None:
253
 
            if not fingerprint in self.acceptable_keys:                
 
259
            if not fingerprint in self.acceptable_keys:
254
260
                return SIGNATURE_KEY_MISSING, fingerprint[-8:]
255
261
        # Check the signature actually matches the testament.
256
262
        # test_verify_bad_testament()
257
263
        if testament != plain_output.getvalue():
258
 
            return SIGNATURE_NOT_VALID, None 
 
264
            return SIGNATURE_NOT_VALID, None
259
265
        # Yay gpgme set the valid bit.
260
266
        # Can't write a test for this one as you can't set a key to be
261
267
        # trusted using gpgme.
272
278
        # test_verify_unknown_key()
273
279
        if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
274
280
            return SIGNATURE_KEY_MISSING, fingerprint[-8:]
275
 
        # Summary isn't set if sig is valid but key is untrusted
276
 
        # but if user has explicity set the key as acceptable we can validate it.
 
281
        # Summary isn't set if sig is valid but key is untrusted but if user
 
282
        # has explicity set the key as acceptable we can validate it.
277
283
        if result[0].summary == 0 and self.acceptable_keys is not None:
278
284
            if fingerprint in self.acceptable_keys:
279
285
                # test_verify_untrusted_but_accepted()
280
 
                return SIGNATURE_VALID, None 
 
286
                return SIGNATURE_VALID, None
281
287
        # test_verify_valid_but_untrusted()
282
288
        if result[0].summary == 0 and self.acceptable_keys is None:
283
289
            return SIGNATURE_NOT_VALID, None
301
307
                                                 "verification result")
302
308
 
303
309
    def set_acceptable_keys(self, command_line_input):
304
 
        """sets the acceptable keys for verifying with this GPGStrategy
 
310
        """Set the acceptable keys for verifying with this GPGStrategy.
305
311
        
306
312
        :param command_line_input: comma separated list of patterns from
307
313
                                command line
308
314
        :return: nothing
309
315
        """
310
316
        key_patterns = None
311
 
        acceptable_keys_config = self._config.acceptable_keys()
 
317
        acceptable_keys_config = self._config_stack.get('acceptable_keys')
312
318
        try:
313
319
            if isinstance(acceptable_keys_config, unicode):
314
320
                acceptable_keys_config = str(acceptable_keys_config)
315
321
        except UnicodeEncodeError:
316
 
            #gpg Context.keylist(pattern) does not like unicode
317
 
            raise errors.BzrCommandError(gettext('Only ASCII permitted in option names'))
 
322
            # gpg Context.keylist(pattern) does not like unicode
 
323
            raise errors.BzrCommandError(
 
324
                gettext('Only ASCII permitted in option names'))
318
325
 
319
326
        if acceptable_keys_config is not None:
320
327
            key_patterns = acceptable_keys_config
321
 
        if command_line_input is not None: #command line overrides config
 
328
        if command_line_input is not None: # command line overrides config
322
329
            key_patterns = command_line_input
323
330
        if key_patterns is not None:
324
331
            patterns = key_patterns.split(",")
376
383
                signers[uid] += 1
377
384
        result = []
378
385
        for uid, number in signers.items():
379
 
             result.append( ngettext(u"{0} signed {1} commit", 
 
386
             result.append( ngettext(u"{0} signed {1} commit",
380
387
                             u"{0} signed {1} commits",
381
388
                             number).format(uid, number) )
382
389
        return result
393
400
                signers[authors] += 1
394
401
        result = []
395
402
        for authors, number in signers.items():
396
 
            result.append( ngettext(u"{0} commit by author {1}", 
 
403
            result.append( ngettext(u"{0} commit by author {1}",
397
404
                                 u"{0} commits by author {1}",
398
405
                                 number).format(number, authors) )
399
406
        return result
409
416
                signers[authors] += 1
410
417
        result = []
411
418
        for authors, number in signers.items():
412
 
            result.append( ngettext(u"{0} commit by author {1}", 
 
419
            result.append( ngettext(u"{0} commit by author {1}",
413
420
                                 u"{0} commits by author {1}",
414
421
                                 number).format(number, authors) )
415
422
        return result
423
430
                signers[fingerprint] += 1
424
431
        result = []
425
432
        for fingerprint, number in signers.items():
426
 
            result.append( ngettext(u"Unknown key {0} signed {1} commit", 
 
433
            result.append( ngettext(u"Unknown key {0} signed {1} commit",
427
434
                                 u"Unknown key {0} signed {1} commits",
428
435
                                 number).format(fingerprint, number) )
429
436
        return result
441
448
                fingerprint_to_authors[fingerprint] = authors
442
449
        result = []
443
450
        for fingerprint, number in signers.items():
444
 
            result.append(ngettext(u"{0} commit by author {1} with "\
445
 
                                    "key {2} now expired", 
446
 
                                   u"{0} commits by author {1} with key {2} now "\
447
 
                                    "expired",
448
 
                                    number).format(number,
449
 
                            fingerprint_to_authors[fingerprint], fingerprint) )
 
451
            result.append(
 
452
                ngettext(u"{0} commit by author {1} with key {2} now expired",
 
453
                         u"{0} commits by author {1} with key {2} now expired",
 
454
                         number).format(
 
455
                    number, fingerprint_to_authors[fingerprint], fingerprint) )
450
456
        return result
451
457
 
452
458
    def valid_commits_message(self, count):