~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/gpg.py

  • Committer: Patch Queue Manager
  • Date: 2014-10-06 16:32:42 UTC
  • mfrom: (6597.2.4 split-diff-tests)
  • Revision ID: pqm@pqm.ubuntu.com-20141006163242-c2cll01cwc24grkk
(vila) Split some tests to be able to get finer grained failures (Vincent
 Ladeuil)

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
315
338
        """
316
 
        key_patterns = None
 
339
        patterns = None
317
340
        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
 
 
326
341
        if acceptable_keys_config is not None:
327
 
            key_patterns = acceptable_keys_config
 
342
            patterns = acceptable_keys_config
328
343
        if command_line_input is not None: # command line overrides config
329
 
            key_patterns = command_line_input
330
 
        if key_patterns is not None:
331
 
            patterns = key_patterns.split(",")
 
344
            patterns = command_line_input.split(',')
332
345
 
 
346
        if patterns:
333
347
            self.acceptable_keys = []
334
348
            for pattern in patterns:
335
349
                result = self.context.keylist(pattern)
343
357
                            "No GnuPG key results for pattern: {0}"
344
358
                                ).format(pattern))
345
359
 
 
360
    @deprecated_method(deprecated_in((2, 6, 0)))
346
361
    def do_verifications(self, revisions, repository,
347
362
                            process_events_callback=None):
348
363
        """do verifications on a set of revisions
349
 
        
 
364
 
350
365
        :param revisions: list of revision ids to verify
351
366
        :param repository: repository object
352
367
        :param process_events_callback: method to call for GUI frontends that
353
 
                                                want to keep their UI refreshed
354
 
        
 
368
            want to keep their UI refreshed
 
369
 
355
370
        :return: count dictionary of results of each type,
356
371
                 result list for each revision,
357
372
                 boolean True if all results are verified successfully
358
373
        """
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)
 
374
        return bulk_verify_signatures(repository, revisions, self,
 
375
            process_events_callback)
376
376
 
 
377
    @deprecated_method(deprecated_in((2, 6, 0)))
377
378
    def verbose_valid_message(self, result):
378
379
        """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
 
 
 
380
        return verbose_valid_message(result)
 
381
 
 
382
    @deprecated_method(deprecated_in((2, 6, 0)))
392
383
    def verbose_not_valid_message(self, result, repo):
393
384
        """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
 
385
        return verbose_not_valid_message(result, repo)
407
386
 
 
387
    @deprecated_method(deprecated_in((2, 6, 0)))
408
388
    def verbose_not_signed_message(self, result, repo):
409
389
        """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
 
390
        return verbose_not_valid_message(result, repo)
423
391
 
 
392
    @deprecated_method(deprecated_in((2, 6, 0)))
424
393
    def verbose_missing_key_message(self, result):
425
394
        """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
 
395
        return verbose_missing_key_message(result)
437
396
 
 
397
    @deprecated_method(deprecated_in((2, 6, 0)))
438
398
    def verbose_expired_key_message(self, result, repo):
439
399
        """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
 
400
        return verbose_expired_key_message(result, repo)
457
401
 
 
402
    @deprecated_method(deprecated_in((2, 6, 0)))
458
403
    def valid_commits_message(self, count):
459
404
        """returns message for number of commits"""
460
 
        return gettext(u"{0} commits with valid signatures").format(
461
 
                                        count[SIGNATURE_VALID])
 
405
        return valid_commits_message(count)
462
406
 
 
407
    @deprecated_method(deprecated_in((2, 6, 0)))
463
408
    def unknown_key_message(self, count):
464
409
        """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])
 
410
        return unknown_key_message(count)
469
411
 
 
412
    @deprecated_method(deprecated_in((2, 6, 0)))
470
413
    def commit_not_valid_message(self, count):
471
414
        """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])
 
415
        return commit_not_valid_message(count)
476
416
 
 
417
    @deprecated_method(deprecated_in((2, 6, 0)))
477
418
    def commit_not_signed_message(self, count):
478
419
        """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])
 
420
        return commit_not_signed_message(count)
483
421
 
 
422
    @deprecated_method(deprecated_in((2, 6, 0)))
484
423
    def expired_commit_message(self, count):
485
424
        """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])
 
425
        return expired_commit_message(count)
 
426
 
 
427
 
 
428
def valid_commits_message(count):
 
429
    """returns message for number of commits"""
 
430
    return gettext(u"{0} commits with valid signatures").format(
 
431
                                    count[SIGNATURE_VALID])
 
432
 
 
433
 
 
434
def unknown_key_message(count):
 
435
    """returns message for number of commits"""
 
436
    return ngettext(u"{0} commit with unknown key",
 
437
                    u"{0} commits with unknown keys",
 
438
                    count[SIGNATURE_KEY_MISSING]).format(
 
439
                                    count[SIGNATURE_KEY_MISSING])
 
440
 
 
441
 
 
442
def commit_not_valid_message(count):
 
443
    """returns message for number of commits"""
 
444
    return ngettext(u"{0} commit not valid",
 
445
                    u"{0} commits not valid",
 
446
                    count[SIGNATURE_NOT_VALID]).format(
 
447
                                        count[SIGNATURE_NOT_VALID])
 
448
 
 
449
 
 
450
def commit_not_signed_message(count):
 
451
    """returns message for number of commits"""
 
452
    return ngettext(u"{0} commit not signed",
 
453
                    u"{0} commits not signed",
 
454
                    count[SIGNATURE_NOT_SIGNED]).format(
 
455
                                    count[SIGNATURE_NOT_SIGNED])
 
456
 
 
457
 
 
458
def expired_commit_message(count):
 
459
    """returns message for number of commits"""
 
460
    return ngettext(u"{0} commit with key now expired",
 
461
                    u"{0} commits with key now expired",
 
462
                    count[SIGNATURE_EXPIRED]).format(
 
463
                                count[SIGNATURE_EXPIRED])
 
464
 
 
465
 
 
466
def verbose_expired_key_message(result, repo):
 
467
    """takes a verify result and returns list of expired key info"""
 
468
    signers = {}
 
469
    fingerprint_to_authors = {}
 
470
    for rev_id, validity, fingerprint in result:
 
471
        if validity == SIGNATURE_EXPIRED:
 
472
            revision = repo.get_revision(rev_id)
 
473
            authors = ', '.join(revision.get_apparent_authors())
 
474
            signers.setdefault(fingerprint, 0)
 
475
            signers[fingerprint] += 1
 
476
            fingerprint_to_authors[fingerprint] = authors
 
477
    result = []
 
478
    for fingerprint, number in signers.items():
 
479
        result.append(
 
480
            ngettext(u"{0} commit by author {1} with key {2} now expired",
 
481
                     u"{0} commits by author {1} with key {2} now expired",
 
482
                     number).format(
 
483
                number, fingerprint_to_authors[fingerprint], fingerprint))
 
484
    return result
 
485
 
 
486
 
 
487
def verbose_valid_message(result):
 
488
    """takes a verify result and returns list of signed commits strings"""
 
489
    signers = {}
 
490
    for rev_id, validity, uid in result:
 
491
        if validity == SIGNATURE_VALID:
 
492
            signers.setdefault(uid, 0)
 
493
            signers[uid] += 1
 
494
    result = []
 
495
    for uid, number in signers.items():
 
496
         result.append(ngettext(u"{0} signed {1} commit",
 
497
                                u"{0} signed {1} commits",
 
498
                                number).format(uid, number))
 
499
    return result
 
500
 
 
501
 
 
502
def verbose_not_valid_message(result, repo):
 
503
    """takes a verify result and returns list of not valid commit info"""
 
504
    signers = {}
 
505
    for rev_id, validity, empty in result:
 
506
        if validity == SIGNATURE_NOT_VALID:
 
507
            revision = repo.get_revision(rev_id)
 
508
            authors = ', '.join(revision.get_apparent_authors())
 
509
            signers.setdefault(authors, 0)
 
510
            signers[authors] += 1
 
511
    result = []
 
512
    for authors, number in signers.items():
 
513
        result.append(ngettext(u"{0} commit by author {1}",
 
514
                               u"{0} commits by author {1}",
 
515
                               number).format(number, authors))
 
516
    return result
 
517
 
 
518
 
 
519
def verbose_not_signed_message(result, repo):
 
520
    """takes a verify result and returns list of not signed commit info"""
 
521
    signers = {}
 
522
    for rev_id, validity, empty in result:
 
523
        if validity == SIGNATURE_NOT_SIGNED:
 
524
            revision = repo.get_revision(rev_id)
 
525
            authors = ', '.join(revision.get_apparent_authors())
 
526
            signers.setdefault(authors, 0)
 
527
            signers[authors] += 1
 
528
    result = []
 
529
    for authors, number in signers.items():
 
530
        result.append(ngettext(u"{0} commit by author {1}",
 
531
                               u"{0} commits by author {1}",
 
532
                               number).format(number, authors))
 
533
    return result
 
534
 
 
535
 
 
536
def verbose_missing_key_message(result):
 
537
    """takes a verify result and returns list of missing key info"""
 
538
    signers = {}
 
539
    for rev_id, validity, fingerprint in result:
 
540
        if validity == SIGNATURE_KEY_MISSING:
 
541
            signers.setdefault(fingerprint, 0)
 
542
            signers[fingerprint] += 1
 
543
    result = []
 
544
    for fingerprint, number in signers.items():
 
545
        result.append(ngettext(u"Unknown key {0} signed {1} commit",
 
546
                               u"Unknown key {0} signed {1} commits",
 
547
                               number).format(fingerprint, number))
 
548
    return result