~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/gpg.py

  • Committer: Ross Lagerwall
  • Date: 2012-08-07 06:32:51 UTC
  • mto: (6437.63.5 2.5)
  • mto: This revision was merged to the branch mainline in revision 6558.
  • Revision ID: rosslagerwall@gmail.com-20120807063251-x9p03ghg2ws8oqjc
Add bzrlib/locale to .bzrignore

bzrlib/locale is generated with ./setup.py build_mo which is in turn called
by ./setup.py build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2009, 2011, 2012, 2013, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2011 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
40
40
    )
41
41
""")
42
42
 
43
 
from bzrlib.symbol_versioning import (
44
 
    deprecated_in,
45
 
    deprecated_method,
46
 
    )
47
 
 
48
43
#verification results
49
44
SIGNATURE_VALID = 0
50
45
SIGNATURE_KEY_MISSING = 1
53
48
SIGNATURE_EXPIRED = 4
54
49
 
55
50
 
56
 
def bulk_verify_signatures(repository, revids, strategy,
57
 
        process_events_callback=None):
58
 
    """Do verifications on a set of revisions
59
 
 
60
 
    :param repository: repository object
61
 
    :param revids: list of revision ids to verify
62
 
    :param strategy: GPG strategy to use
63
 
    :param process_events_callback: method to call for GUI frontends that
64
 
        want to keep their UI refreshed
65
 
 
66
 
    :return: count dictionary of results of each type,
67
 
             result list for each revision,
68
 
             boolean True if all results are verified successfully
69
 
    """
70
 
    count = {SIGNATURE_VALID: 0,
71
 
             SIGNATURE_KEY_MISSING: 0,
72
 
             SIGNATURE_NOT_VALID: 0,
73
 
             SIGNATURE_NOT_SIGNED: 0,
74
 
             SIGNATURE_EXPIRED: 0}
75
 
    result = []
76
 
    all_verifiable = True
77
 
    total = len(revids)
78
 
    pb = ui.ui_factory.nested_progress_bar()
79
 
    try:
80
 
        for i, (rev_id, verification_result, uid) in enumerate(
81
 
                repository.verify_revision_signatures(
82
 
                    revids, strategy)):
83
 
            pb.update("verifying signatures", i, total)
84
 
            result.append([rev_id, verification_result, uid])
85
 
            count[verification_result] += 1
86
 
            if verification_result != SIGNATURE_VALID:
87
 
                all_verifiable = False
88
 
            if process_events_callback is not None:
89
 
                process_events_callback()
90
 
    finally:
91
 
        pb.finished()
92
 
    return (count, result, all_verifiable)
93
 
 
94
 
 
95
51
class DisabledGPGStrategy(object):
96
52
    """A GPG Strategy that makes everything fail."""
97
53
 
142
98
                else:
143
99
                    self.acceptable_keys.append(pattern)
144
100
 
145
 
    @deprecated_method(deprecated_in((2, 6, 0)))
146
101
    def do_verifications(self, revisions, repository):
147
 
        return bulk_verify_signatures(repository, revisions, self)
 
102
        count = {SIGNATURE_VALID: 0,
 
103
                 SIGNATURE_KEY_MISSING: 0,
 
104
                 SIGNATURE_NOT_VALID: 0,
 
105
                 SIGNATURE_NOT_SIGNED: 0,
 
106
                 SIGNATURE_EXPIRED: 0}
 
107
        result = []
 
108
        all_verifiable = True
 
109
        for rev_id in revisions:
 
110
            verification_result, uid =\
 
111
                repository.verify_revision_signature(rev_id,self)
 
112
            result.append([rev_id, verification_result, uid])
 
113
            count[verification_result] += 1
 
114
            if verification_result != SIGNATURE_VALID:
 
115
                all_verifiable = False
 
116
        return (count, result, all_verifiable)
148
117
 
149
 
    @deprecated_method(deprecated_in((2, 6, 0)))
150
118
    def valid_commits_message(self, count):
151
 
        return valid_commits_message(count)
 
119
        return gettext(u"{0} commits with valid signatures").format(
 
120
                                        count[SIGNATURE_VALID])
152
121
 
153
 
    @deprecated_method(deprecated_in((2, 6, 0)))
154
122
    def unknown_key_message(self, count):
155
 
        return unknown_key_message(count)
 
123
        return ngettext(u"{0} commit with unknown key",
 
124
                             u"{0} commits with unknown keys",
 
125
                             count[SIGNATURE_KEY_MISSING]).format(
 
126
                                        count[SIGNATURE_KEY_MISSING])
156
127
 
157
 
    @deprecated_method(deprecated_in((2, 6, 0)))
158
128
    def commit_not_valid_message(self, count):
159
 
        return commit_not_valid_message(count)
 
129
        return ngettext(u"{0} commit not valid",
 
130
                             u"{0} commits not valid",
 
131
                             count[SIGNATURE_NOT_VALID]).format(
 
132
                                            count[SIGNATURE_NOT_VALID])
160
133
 
161
 
    @deprecated_method(deprecated_in((2, 6, 0)))
162
134
    def commit_not_signed_message(self, count):
163
 
        return commit_not_signed_message(count)
 
135
        return ngettext(u"{0} commit not signed",
 
136
                             u"{0} commits not signed",
 
137
                             count[SIGNATURE_NOT_SIGNED]).format(
 
138
                                        count[SIGNATURE_NOT_SIGNED])
164
139
 
165
 
    @deprecated_method(deprecated_in((2, 6, 0)))
166
140
    def expired_commit_message(self, count):
167
 
        return expired_commit_message(count)
 
141
        return ngettext(u"{0} commit with key now expired",
 
142
                        u"{0} commits with key now expired",
 
143
                        count[SIGNATURE_EXPIRED]).format(
 
144
                                        count[SIGNATURE_EXPIRED])
168
145
 
169
146
 
170
147
def _set_gpg_tty():
253
230
 
254
231
    def verify(self, content, testament):
255
232
        """Check content has a valid signature.
256
 
 
 
233
        
257
234
        :param content: the commit signature
258
235
        :param testament: the valid testament string for the commit
259
 
 
 
236
        
260
237
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid
261
238
        """
262
239
        try:
322
299
                return SIGNATURE_NOT_VALID, None
323
300
        # A signature from a revoked key gets this.
324
301
        # test_verify_revoked_signature()
325
 
        if ((result[0].summary & gpgme.SIGSUM_SYS_ERROR
326
 
             or result[0].status.strerror == 'Certificate revoked')):
 
302
        if result[0].summary & gpgme.SIGSUM_SYS_ERROR:
327
303
            return SIGNATURE_NOT_VALID, None
328
304
        # Other error types such as revoked keys should (I think) be caught by
329
305
        # SIGSUM_RED so anything else means something is buggy.
330
 
        raise errors.SignatureVerificationFailed(
331
 
            "Unknown GnuPG key verification result")
 
306
        raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
 
307
                                                 "verification result")
332
308
 
333
309
    def set_acceptable_keys(self, command_line_input):
334
310
        """Set the acceptable keys for verifying with this GPGStrategy.
335
 
 
 
311
        
336
312
        :param command_line_input: comma separated list of patterns from
337
313
                                command line
338
314
        :return: nothing
339
315
        """
340
 
        patterns = None
 
316
        key_patterns = None
341
317
        acceptable_keys_config = self._config_stack.get('acceptable_keys')
 
318
        try:
 
319
            if isinstance(acceptable_keys_config, unicode):
 
320
                acceptable_keys_config = str(acceptable_keys_config)
 
321
        except UnicodeEncodeError:
 
322
            # gpg Context.keylist(pattern) does not like unicode
 
323
            raise errors.BzrCommandError(
 
324
                gettext('Only ASCII permitted in option names'))
 
325
 
342
326
        if acceptable_keys_config is not None:
343
 
            patterns = acceptable_keys_config
 
327
            key_patterns = acceptable_keys_config
344
328
        if command_line_input is not None: # command line overrides config
345
 
            patterns = command_line_input.split(',')
 
329
            key_patterns = command_line_input
 
330
        if key_patterns is not None:
 
331
            patterns = key_patterns.split(",")
346
332
 
347
 
        if patterns:
348
333
            self.acceptable_keys = []
349
334
            for pattern in patterns:
350
335
                result = self.context.keylist(pattern)
358
343
                            "No GnuPG key results for pattern: {0}"
359
344
                                ).format(pattern))
360
345
 
361
 
    @deprecated_method(deprecated_in((2, 6, 0)))
362
346
    def do_verifications(self, revisions, repository,
363
347
                            process_events_callback=None):
364
348
        """do verifications on a set of revisions
365
 
 
 
349
        
366
350
        :param revisions: list of revision ids to verify
367
351
        :param repository: repository object
368
352
        :param process_events_callback: method to call for GUI frontends that
369
 
            want to keep their UI refreshed
370
 
 
 
353
                                                want to keep their UI refreshed
 
354
        
371
355
        :return: count dictionary of results of each type,
372
356
                 result list for each revision,
373
357
                 boolean True if all results are verified successfully
374
358
        """
375
 
        return bulk_verify_signatures(repository, revisions, self,
376
 
            process_events_callback)
 
359
        count = {SIGNATURE_VALID: 0,
 
360
                 SIGNATURE_KEY_MISSING: 0,
 
361
                 SIGNATURE_NOT_VALID: 0,
 
362
                 SIGNATURE_NOT_SIGNED: 0,
 
363
                 SIGNATURE_EXPIRED: 0}
 
364
        result = []
 
365
        all_verifiable = True
 
366
        for rev_id in revisions:
 
367
            verification_result, uid =\
 
368
                repository.verify_revision_signature(rev_id, self)
 
369
            result.append([rev_id, verification_result, uid])
 
370
            count[verification_result] += 1
 
371
            if verification_result != SIGNATURE_VALID:
 
372
                all_verifiable = False
 
373
            if process_events_callback is not None:
 
374
                process_events_callback()
 
375
        return (count, result, all_verifiable)
377
376
 
378
 
    @deprecated_method(deprecated_in((2, 6, 0)))
379
377
    def verbose_valid_message(self, result):
380
378
        """takes a verify result and returns list of signed commits strings"""
381
 
        return verbose_valid_message(result)
382
 
 
383
 
    @deprecated_method(deprecated_in((2, 6, 0)))
 
379
        signers = {}
 
380
        for rev_id, validity, uid in result:
 
381
            if validity == SIGNATURE_VALID:
 
382
                signers.setdefault(uid, 0)
 
383
                signers[uid] += 1
 
384
        result = []
 
385
        for uid, number in signers.items():
 
386
             result.append( ngettext(u"{0} signed {1} commit",
 
387
                             u"{0} signed {1} commits",
 
388
                             number).format(uid, number) )
 
389
        return result
 
390
 
 
391
 
384
392
    def verbose_not_valid_message(self, result, repo):
385
393
        """takes a verify result and returns list of not valid commit info"""
386
 
        return verbose_not_valid_message(result, repo)
 
394
        signers = {}
 
395
        for rev_id, validity, empty in result:
 
396
            if validity == SIGNATURE_NOT_VALID:
 
397
                revision = repo.get_revision(rev_id)
 
398
                authors = ', '.join(revision.get_apparent_authors())
 
399
                signers.setdefault(authors, 0)
 
400
                signers[authors] += 1
 
401
        result = []
 
402
        for authors, number in signers.items():
 
403
            result.append( ngettext(u"{0} commit by author {1}",
 
404
                                 u"{0} commits by author {1}",
 
405
                                 number).format(number, authors) )
 
406
        return result
387
407
 
388
 
    @deprecated_method(deprecated_in((2, 6, 0)))
389
408
    def verbose_not_signed_message(self, result, repo):
390
409
        """takes a verify result and returns list of not signed commit info"""
391
 
        return verbose_not_valid_message(result, repo)
 
410
        signers = {}
 
411
        for rev_id, validity, empty in result:
 
412
            if validity == SIGNATURE_NOT_SIGNED:
 
413
                revision = repo.get_revision(rev_id)
 
414
                authors = ', '.join(revision.get_apparent_authors())
 
415
                signers.setdefault(authors, 0)
 
416
                signers[authors] += 1
 
417
        result = []
 
418
        for authors, number in signers.items():
 
419
            result.append( ngettext(u"{0} commit by author {1}",
 
420
                                 u"{0} commits by author {1}",
 
421
                                 number).format(number, authors) )
 
422
        return result
392
423
 
393
 
    @deprecated_method(deprecated_in((2, 6, 0)))
394
424
    def verbose_missing_key_message(self, result):
395
425
        """takes a verify result and returns list of missing key info"""
396
 
        return verbose_missing_key_message(result)
 
426
        signers = {}
 
427
        for rev_id, validity, fingerprint in result:
 
428
            if validity == SIGNATURE_KEY_MISSING:
 
429
                signers.setdefault(fingerprint, 0)
 
430
                signers[fingerprint] += 1
 
431
        result = []
 
432
        for fingerprint, number in signers.items():
 
433
            result.append( ngettext(u"Unknown key {0} signed {1} commit",
 
434
                                 u"Unknown key {0} signed {1} commits",
 
435
                                 number).format(fingerprint, number) )
 
436
        return result
397
437
 
398
 
    @deprecated_method(deprecated_in((2, 6, 0)))
399
438
    def verbose_expired_key_message(self, result, repo):
400
439
        """takes a verify result and returns list of expired key info"""
401
 
        return verbose_expired_key_message(result, repo)
 
440
        signers = {}
 
441
        fingerprint_to_authors = {}
 
442
        for rev_id, validity, fingerprint in result:
 
443
            if validity == SIGNATURE_EXPIRED:
 
444
                revision = repo.get_revision(rev_id)
 
445
                authors = ', '.join(revision.get_apparent_authors())
 
446
                signers.setdefault(fingerprint, 0)
 
447
                signers[fingerprint] += 1
 
448
                fingerprint_to_authors[fingerprint] = authors
 
449
        result = []
 
450
        for fingerprint, number in signers.items():
 
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) )
 
456
        return result
402
457
 
403
 
    @deprecated_method(deprecated_in((2, 6, 0)))
404
458
    def valid_commits_message(self, count):
405
459
        """returns message for number of commits"""
406
 
        return valid_commits_message(count)
 
460
        return gettext(u"{0} commits with valid signatures").format(
 
461
                                        count[SIGNATURE_VALID])
407
462
 
408
 
    @deprecated_method(deprecated_in((2, 6, 0)))
409
463
    def unknown_key_message(self, count):
410
464
        """returns message for number of commits"""
411
 
        return unknown_key_message(count)
 
465
        return ngettext(u"{0} commit with unknown key",
 
466
                        u"{0} commits with unknown keys",
 
467
                        count[SIGNATURE_KEY_MISSING]).format(
 
468
                                        count[SIGNATURE_KEY_MISSING])
412
469
 
413
 
    @deprecated_method(deprecated_in((2, 6, 0)))
414
470
    def commit_not_valid_message(self, count):
415
471
        """returns message for number of commits"""
416
 
        return commit_not_valid_message(count)
 
472
        return ngettext(u"{0} commit not valid",
 
473
                        u"{0} commits not valid",
 
474
                        count[SIGNATURE_NOT_VALID]).format(
 
475
                                            count[SIGNATURE_NOT_VALID])
417
476
 
418
 
    @deprecated_method(deprecated_in((2, 6, 0)))
419
477
    def commit_not_signed_message(self, count):
420
478
        """returns message for number of commits"""
421
 
        return commit_not_signed_message(count)
 
479
        return ngettext(u"{0} commit not signed",
 
480
                        u"{0} commits not signed",
 
481
                        count[SIGNATURE_NOT_SIGNED]).format(
 
482
                                        count[SIGNATURE_NOT_SIGNED])
422
483
 
423
 
    @deprecated_method(deprecated_in((2, 6, 0)))
424
484
    def expired_commit_message(self, count):
425
485
        """returns message for number of commits"""
426
 
        return expired_commit_message(count)
427
 
 
428
 
 
429
 
def valid_commits_message(count):
430
 
    """returns message for number of commits"""
431
 
    return gettext(u"{0} commits with valid signatures").format(
432
 
                                    count[SIGNATURE_VALID])
433
 
 
434
 
 
435
 
def unknown_key_message(count):
436
 
    """returns message for number of commits"""
437
 
    return ngettext(u"{0} commit with unknown key",
438
 
                    u"{0} commits with unknown keys",
439
 
                    count[SIGNATURE_KEY_MISSING]).format(
440
 
                                    count[SIGNATURE_KEY_MISSING])
441
 
 
442
 
 
443
 
def commit_not_valid_message(count):
444
 
    """returns message for number of commits"""
445
 
    return ngettext(u"{0} commit not valid",
446
 
                    u"{0} commits not valid",
447
 
                    count[SIGNATURE_NOT_VALID]).format(
448
 
                                        count[SIGNATURE_NOT_VALID])
449
 
 
450
 
 
451
 
def commit_not_signed_message(count):
452
 
    """returns message for number of commits"""
453
 
    return ngettext(u"{0} commit not signed",
454
 
                    u"{0} commits not signed",
455
 
                    count[SIGNATURE_NOT_SIGNED]).format(
456
 
                                    count[SIGNATURE_NOT_SIGNED])
457
 
 
458
 
 
459
 
def expired_commit_message(count):
460
 
    """returns message for number of commits"""
461
 
    return ngettext(u"{0} commit with key now expired",
462
 
                    u"{0} commits with key now expired",
463
 
                    count[SIGNATURE_EXPIRED]).format(
464
 
                                count[SIGNATURE_EXPIRED])
465
 
 
466
 
 
467
 
def verbose_expired_key_message(result, repo):
468
 
    """takes a verify result and returns list of expired key info"""
469
 
    signers = {}
470
 
    fingerprint_to_authors = {}
471
 
    for rev_id, validity, fingerprint in result:
472
 
        if validity == SIGNATURE_EXPIRED:
473
 
            revision = repo.get_revision(rev_id)
474
 
            authors = ', '.join(revision.get_apparent_authors())
475
 
            signers.setdefault(fingerprint, 0)
476
 
            signers[fingerprint] += 1
477
 
            fingerprint_to_authors[fingerprint] = authors
478
 
    result = []
479
 
    for fingerprint, number in signers.items():
480
 
        result.append(
481
 
            ngettext(u"{0} commit by author {1} with key {2} now expired",
482
 
                     u"{0} commits by author {1} with key {2} now expired",
483
 
                     number).format(
484
 
                number, fingerprint_to_authors[fingerprint], fingerprint))
485
 
    return result
486
 
 
487
 
 
488
 
def verbose_valid_message(result):
489
 
    """takes a verify result and returns list of signed commits strings"""
490
 
    signers = {}
491
 
    for rev_id, validity, uid in result:
492
 
        if validity == SIGNATURE_VALID:
493
 
            signers.setdefault(uid, 0)
494
 
            signers[uid] += 1
495
 
    result = []
496
 
    for uid, number in signers.items():
497
 
         result.append(ngettext(u"{0} signed {1} commit",
498
 
                                u"{0} signed {1} commits",
499
 
                                number).format(uid, number))
500
 
    return result
501
 
 
502
 
 
503
 
def verbose_not_valid_message(result, repo):
504
 
    """takes a verify result and returns list of not valid commit info"""
505
 
    signers = {}
506
 
    for rev_id, validity, empty in result:
507
 
        if validity == SIGNATURE_NOT_VALID:
508
 
            revision = repo.get_revision(rev_id)
509
 
            authors = ', '.join(revision.get_apparent_authors())
510
 
            signers.setdefault(authors, 0)
511
 
            signers[authors] += 1
512
 
    result = []
513
 
    for authors, number in signers.items():
514
 
        result.append(ngettext(u"{0} commit by author {1}",
515
 
                               u"{0} commits by author {1}",
516
 
                               number).format(number, authors))
517
 
    return result
518
 
 
519
 
 
520
 
def verbose_not_signed_message(result, repo):
521
 
    """takes a verify result and returns list of not signed commit info"""
522
 
    signers = {}
523
 
    for rev_id, validity, empty in result:
524
 
        if validity == SIGNATURE_NOT_SIGNED:
525
 
            revision = repo.get_revision(rev_id)
526
 
            authors = ', '.join(revision.get_apparent_authors())
527
 
            signers.setdefault(authors, 0)
528
 
            signers[authors] += 1
529
 
    result = []
530
 
    for authors, number in signers.items():
531
 
        result.append(ngettext(u"{0} commit by author {1}",
532
 
                               u"{0} commits by author {1}",
533
 
                               number).format(number, authors))
534
 
    return result
535
 
 
536
 
 
537
 
def verbose_missing_key_message(result):
538
 
    """takes a verify result and returns list of missing key info"""
539
 
    signers = {}
540
 
    for rev_id, validity, fingerprint in result:
541
 
        if validity == SIGNATURE_KEY_MISSING:
542
 
            signers.setdefault(fingerprint, 0)
543
 
            signers[fingerprint] += 1
544
 
    result = []
545
 
    for fingerprint, number in signers.items():
546
 
        result.append(ngettext(u"Unknown key {0} signed {1} commit",
547
 
                               u"Unknown key {0} signed {1} commits",
548
 
                               number).format(fingerprint, number))
549
 
    return result
 
486
        return ngettext(u"{0} commit with key now expired",
 
487
                        u"{0} commits with key now expired",
 
488
                        count[SIGNATURE_EXPIRED]).format(
 
489
                                    count[SIGNATURE_EXPIRED])