~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/gpg.py

  • Committer: Patch Queue Manager
  • Date: 2012-03-12 12:35:59 UTC
  • mfrom: (6491.1.7 repo-verify-signatures)
  • Revision ID: pqm@pqm.ubuntu.com-20120312123559-g4tqzz3790kszu03
(jelmer) Various fixes for 'bzr verify-signatures'. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
    )
41
41
""")
42
42
 
 
43
from bzrlib.symbol_versioning import (
 
44
    deprecated_in,
 
45
    deprecated_method,
 
46
    )
 
47
 
43
48
#verification results
44
49
SIGNATURE_VALID = 0
45
50
SIGNATURE_KEY_MISSING = 1
48
53
SIGNATURE_EXPIRED = 4
49
54
 
50
55
 
 
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
 
51
95
class DisabledGPGStrategy(object):
52
96
    """A GPG Strategy that makes everything fail."""
53
97
 
98
142
                else:
99
143
                    self.acceptable_keys.append(pattern)
100
144
 
 
145
    @deprecated_method(deprecated_in((2, 6, 0)))
101
146
    def do_verifications(self, revisions, repository):
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)
 
147
        return bulk_verify_signatures(repository, revisions, self)
117
148
 
 
149
    @deprecated_method(deprecated_in((2, 6, 0)))
118
150
    def valid_commits_message(self, count):
119
 
        return gettext(u"{0} commits with valid signatures").format(
120
 
                                        count[SIGNATURE_VALID])
 
151
        return valid_commits_message(count)
121
152
 
 
153
    @deprecated_method(deprecated_in((2, 6, 0)))
122
154
    def unknown_key_message(self, 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])
 
155
        return unknown_key_message(count)
127
156
 
 
157
    @deprecated_method(deprecated_in((2, 6, 0)))
128
158
    def commit_not_valid_message(self, 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])
 
159
        return commit_not_valid_message(count)
133
160
 
 
161
    @deprecated_method(deprecated_in((2, 6, 0)))
134
162
    def commit_not_signed_message(self, 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])
 
163
        return commit_not_signed_message(count)
139
164
 
 
165
    @deprecated_method(deprecated_in((2, 6, 0)))
140
166
    def expired_commit_message(self, 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])
 
167
        return expired_commit_message(count)
145
168
 
146
169
 
147
170
def _set_gpg_tty():
230
253
 
231
254
    def verify(self, content, testament):
232
255
        """Check content has a valid signature.
233
 
        
 
256
 
234
257
        :param content: the commit signature
235
258
        :param testament: the valid testament string for the commit
236
 
        
 
259
 
237
260
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid
238
261
        """
239
262
        try:
308
331
 
309
332
    def set_acceptable_keys(self, command_line_input):
310
333
        """Set the acceptable keys for verifying with this GPGStrategy.
311
 
        
 
334
 
312
335
        :param command_line_input: comma separated list of patterns from
313
336
                                command line
314
337
        :return: nothing
343
366
                            "No GnuPG key results for pattern: {0}"
344
367
                                ).format(pattern))
345
368
 
 
369
    @deprecated_method(deprecated_in((2, 6, 0)))
346
370
    def do_verifications(self, revisions, repository,
347
371
                            process_events_callback=None):
348
372
        """do verifications on a set of revisions
349
 
        
 
373
 
350
374
        :param revisions: list of revision ids to verify
351
375
        :param repository: repository object
352
376
        :param process_events_callback: method to call for GUI frontends that
353
 
                                                want to keep their UI refreshed
354
 
        
 
377
            want to keep their UI refreshed
 
378
 
355
379
        :return: count dictionary of results of each type,
356
380
                 result list for each revision,
357
381
                 boolean True if all results are verified successfully
358
382
        """
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)
 
383
        return bulk_verify_signatures(repository, revisions, self,
 
384
            process_events_callback)
376
385
 
 
386
    @deprecated_method(deprecated_in((2, 6, 0)))
377
387
    def verbose_valid_message(self, result):
378
388
        """takes a verify result and returns list of signed commits strings"""
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
 
 
 
389
        return verbose_valid_message(result)
 
390
 
 
391
    @deprecated_method(deprecated_in((2, 6, 0)))
392
392
    def verbose_not_valid_message(self, result, repo):
393
393
        """takes a verify result and returns list of not valid commit info"""
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
 
394
        return verbose_not_valid_message(result, repo)
407
395
 
 
396
    @deprecated_method(deprecated_in((2, 6, 0)))
408
397
    def verbose_not_signed_message(self, result, repo):
409
398
        """takes a verify result and returns list of not signed commit info"""
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
 
399
        return verbose_not_valid_message(result, repo)
423
400
 
 
401
    @deprecated_method(deprecated_in((2, 6, 0)))
424
402
    def verbose_missing_key_message(self, result):
425
403
        """takes a verify result and returns list of missing key info"""
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
 
404
        return verbose_missing_key_message(result)
437
405
 
 
406
    @deprecated_method(deprecated_in((2, 6, 0)))
438
407
    def verbose_expired_key_message(self, result, repo):
439
408
        """takes a verify result and returns list of expired key info"""
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
 
409
        return verbose_expired_key_message(result, repo)
457
410
 
 
411
    @deprecated_method(deprecated_in((2, 6, 0)))
458
412
    def valid_commits_message(self, count):
459
413
        """returns message for number of commits"""
460
 
        return gettext(u"{0} commits with valid signatures").format(
461
 
                                        count[SIGNATURE_VALID])
 
414
        return valid_commits_message(count)
462
415
 
 
416
    @deprecated_method(deprecated_in((2, 6, 0)))
463
417
    def unknown_key_message(self, count):
464
418
        """returns message for number of commits"""
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])
 
419
        return unknown_key_message(count)
469
420
 
 
421
    @deprecated_method(deprecated_in((2, 6, 0)))
470
422
    def commit_not_valid_message(self, count):
471
423
        """returns message for number of commits"""
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])
 
424
        return commit_not_valid_message(count)
476
425
 
 
426
    @deprecated_method(deprecated_in((2, 6, 0)))
477
427
    def commit_not_signed_message(self, count):
478
428
        """returns message for number of commits"""
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])
 
429
        return commit_not_signed_message(count)
483
430
 
 
431
    @deprecated_method(deprecated_in((2, 6, 0)))
484
432
    def expired_commit_message(self, count):
485
433
        """returns message for number of commits"""
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])
 
434
        return expired_commit_message(count)
 
435
 
 
436
 
 
437
def valid_commits_message(count):
 
438
    """returns message for number of commits"""
 
439
    return gettext(u"{0} commits with valid signatures").format(
 
440
                                    count[SIGNATURE_VALID])
 
441
 
 
442
 
 
443
def unknown_key_message(count):
 
444
    """returns message for number of commits"""
 
445
    return ngettext(u"{0} commit with unknown key",
 
446
                    u"{0} commits with unknown keys",
 
447
                    count[SIGNATURE_KEY_MISSING]).format(
 
448
                                    count[SIGNATURE_KEY_MISSING])
 
449
 
 
450
 
 
451
def commit_not_valid_message(count):
 
452
    """returns message for number of commits"""
 
453
    return ngettext(u"{0} commit not valid",
 
454
                    u"{0} commits not valid",
 
455
                    count[SIGNATURE_NOT_VALID]).format(
 
456
                                        count[SIGNATURE_NOT_VALID])
 
457
 
 
458
 
 
459
def commit_not_signed_message(count):
 
460
    """returns message for number of commits"""
 
461
    return ngettext(u"{0} commit not signed",
 
462
                    u"{0} commits not signed",
 
463
                    count[SIGNATURE_NOT_SIGNED]).format(
 
464
                                    count[SIGNATURE_NOT_SIGNED])
 
465
 
 
466
 
 
467
def expired_commit_message(count):
 
468
    """returns message for number of commits"""
 
469
    return ngettext(u"{0} commit with key now expired",
 
470
                    u"{0} commits with key now expired",
 
471
                    count[SIGNATURE_EXPIRED]).format(
 
472
                                count[SIGNATURE_EXPIRED])
 
473
 
 
474
 
 
475
def verbose_expired_key_message(result, repo):
 
476
    """takes a verify result and returns list of expired key info"""
 
477
    signers = {}
 
478
    fingerprint_to_authors = {}
 
479
    for rev_id, validity, fingerprint in result:
 
480
        if validity == SIGNATURE_EXPIRED:
 
481
            revision = repo.get_revision(rev_id)
 
482
            authors = ', '.join(revision.get_apparent_authors())
 
483
            signers.setdefault(fingerprint, 0)
 
484
            signers[fingerprint] += 1
 
485
            fingerprint_to_authors[fingerprint] = authors
 
486
    result = []
 
487
    for fingerprint, number in signers.items():
 
488
        result.append(
 
489
            ngettext(u"{0} commit by author {1} with key {2} now expired",
 
490
                     u"{0} commits by author {1} with key {2} now expired",
 
491
                     number).format(
 
492
                number, fingerprint_to_authors[fingerprint], fingerprint))
 
493
    return result
 
494
 
 
495
 
 
496
def verbose_valid_message(result):
 
497
    """takes a verify result and returns list of signed commits strings"""
 
498
    signers = {}
 
499
    for rev_id, validity, uid in result:
 
500
        if validity == SIGNATURE_VALID:
 
501
            signers.setdefault(uid, 0)
 
502
            signers[uid] += 1
 
503
    result = []
 
504
    for uid, number in signers.items():
 
505
         result.append(ngettext(u"{0} signed {1} commit",
 
506
                                u"{0} signed {1} commits",
 
507
                                number).format(uid, number))
 
508
    return result
 
509
 
 
510
 
 
511
def verbose_not_valid_message(result, repo):
 
512
    """takes a verify result and returns list of not valid commit info"""
 
513
    signers = {}
 
514
    for rev_id, validity, empty in result:
 
515
        if validity == SIGNATURE_NOT_VALID:
 
516
            revision = repo.get_revision(rev_id)
 
517
            authors = ', '.join(revision.get_apparent_authors())
 
518
            signers.setdefault(authors, 0)
 
519
            signers[authors] += 1
 
520
    result = []
 
521
    for authors, number in signers.items():
 
522
        result.append(ngettext(u"{0} commit by author {1}",
 
523
                               u"{0} commits by author {1}",
 
524
                               number).format(number, authors))
 
525
    return result
 
526
 
 
527
 
 
528
def verbose_not_signed_message(result, repo):
 
529
    """takes a verify result and returns list of not signed commit info"""
 
530
    signers = {}
 
531
    for rev_id, validity, empty in result:
 
532
        if validity == SIGNATURE_NOT_SIGNED:
 
533
            revision = repo.get_revision(rev_id)
 
534
            authors = ', '.join(revision.get_apparent_authors())
 
535
            signers.setdefault(authors, 0)
 
536
            signers[authors] += 1
 
537
    result = []
 
538
    for authors, number in signers.items():
 
539
        result.append(ngettext(u"{0} commit by author {1}",
 
540
                               u"{0} commits by author {1}",
 
541
                               number).format(number, authors))
 
542
    return result
 
543
 
 
544
 
 
545
def verbose_missing_key_message(result):
 
546
    """takes a verify result and returns list of missing key info"""
 
547
    signers = {}
 
548
    for rev_id, validity, fingerprint in result:
 
549
        if validity == SIGNATURE_KEY_MISSING:
 
550
            signers.setdefault(fingerprint, 0)
 
551
            signers[fingerprint] += 1
 
552
    result = []
 
553
    for fingerprint, number in signers.items():
 
554
        result.append(ngettext(u"Unknown key {0} signed {1} commit",
 
555
                               u"Unknown key {0} signed {1} commits",
 
556
                               number).format(fingerprint, number))
 
557
    return result