103
143
self.acceptable_keys.append(pattern)
145
@deprecated_method(deprecated_in((2, 6, 0)))
105
146
def do_verifications(self, revisions, repository):
106
count = {SIGNATURE_VALID: 0,
107
SIGNATURE_KEY_MISSING: 0,
108
SIGNATURE_NOT_VALID: 0,
109
SIGNATURE_NOT_SIGNED: 0}
111
all_verifiable = True
112
for rev_id in revisions:
113
verification_result, uid =\
114
repository.verify_revision(rev_id,self)
115
result.append([rev_id, verification_result, uid])
116
count[verification_result] += 1
117
if verification_result != SIGNATURE_VALID:
118
all_verifiable = False
119
return (count, result, all_verifiable)
147
return bulk_verify_signatures(repository, revisions, self)
149
@deprecated_method(deprecated_in((2, 6, 0)))
121
150
def valid_commits_message(self, count):
122
return i18n.gettext("{0} commits with valid signatures").format(
123
count[SIGNATURE_VALID])
151
return valid_commits_message(count)
153
@deprecated_method(deprecated_in((2, 6, 0)))
125
154
def unknown_key_message(self, count):
126
return i18n.ngettext("{0} commit with unknown key",
127
"{0} commits with unknown keys",
128
count[SIGNATURE_KEY_MISSING]).format(
129
count[SIGNATURE_KEY_MISSING])
155
return unknown_key_message(count)
157
@deprecated_method(deprecated_in((2, 6, 0)))
131
158
def commit_not_valid_message(self, count):
132
return i18n.ngettext("{0} commit not valid",
133
"{0} commits not valid",
134
count[SIGNATURE_NOT_VALID]).format(
135
count[SIGNATURE_NOT_VALID])
159
return commit_not_valid_message(count)
161
@deprecated_method(deprecated_in((2, 6, 0)))
137
162
def commit_not_signed_message(self, count):
138
return i18n.ngettext("{0} commit not signed",
139
"{0} commits not signed",
140
count[SIGNATURE_NOT_SIGNED]).format(
141
count[SIGNATURE_NOT_SIGNED])
163
return commit_not_signed_message(count)
165
@deprecated_method(deprecated_in((2, 6, 0)))
166
def expired_commit_message(self, count):
167
return expired_commit_message(count)
144
170
def _set_gpg_tty():
230
267
signature = StringIO(content)
231
268
plain_output = StringIO()
234
270
result = self.context.verify(signature, None, plain_output)
235
271
except gpgme.GpgmeError,error:
236
272
raise errors.SignatureVerificationFailed(error[2])
274
# No result if input is invalid.
275
# test_verify_invalid()
238
276
if len(result) == 0:
239
277
return SIGNATURE_NOT_VALID, None
278
# User has specified a list of acceptable keys, check our result is in
279
# it. test_verify_unacceptable_key()
240
280
fingerprint = result[0].fpr
241
281
if self.acceptable_keys is not None:
242
282
if not fingerprint in self.acceptable_keys:
243
283
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
284
# Check the signature actually matches the testament.
285
# test_verify_bad_testament()
244
286
if testament != plain_output.getvalue():
245
287
return SIGNATURE_NOT_VALID, None
288
# Yay gpgme set the valid bit.
289
# Can't write a test for this one as you can't set a key to be
290
# trusted using gpgme.
246
291
if result[0].summary & gpgme.SIGSUM_VALID:
247
292
key = self.context.get_key(fingerprint)
248
293
name = key.uids[0].name
249
294
email = key.uids[0].email
250
295
return SIGNATURE_VALID, name + " <" + email + ">"
296
# Sigsum_red indicates a problem, unfortunatly I have not been able
297
# to write any tests which actually set this.
251
298
if result[0].summary & gpgme.SIGSUM_RED:
252
299
return SIGNATURE_NOT_VALID, None
300
# GPG does not know this key.
301
# test_verify_unknown_key()
253
302
if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
254
303
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
255
#summary isn't set if sig is valid but key is untrusted
304
# Summary isn't set if sig is valid but key is untrusted but if user
305
# has explicity set the key as acceptable we can validate it.
256
306
if result[0].summary == 0 and self.acceptable_keys is not None:
257
307
if fingerprint in self.acceptable_keys:
308
# test_verify_untrusted_but_accepted()
258
309
return SIGNATURE_VALID, None
260
return SIGNATURE_KEY_MISSING, None
310
# test_verify_valid_but_untrusted()
311
if result[0].summary == 0 and self.acceptable_keys is None:
312
return SIGNATURE_NOT_VALID, None
313
if result[0].summary & gpgme.SIGSUM_KEY_EXPIRED:
314
expires = self.context.get_key(result[0].fpr).subkeys[0].expires
315
if expires > result[0].timestamp:
316
# The expired key was not expired at time of signing.
317
# test_verify_expired_but_valid()
318
return SIGNATURE_EXPIRED, fingerprint[-8:]
320
# I can't work out how to create a test where the signature
321
# was expired at the time of signing.
322
return SIGNATURE_NOT_VALID, None
323
# A signature from a revoked key gets this.
324
# test_verify_revoked_signature()
325
if result[0].summary & gpgme.SIGSUM_SYS_ERROR:
326
return SIGNATURE_NOT_VALID, None
327
# Other error types such as revoked keys should (I think) be caught by
328
# SIGSUM_RED so anything else means something is buggy.
261
329
raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
262
330
"verification result")
264
332
def set_acceptable_keys(self, command_line_input):
265
"""sets the acceptable keys for verifying with this GPGStrategy
333
"""Set the acceptable keys for verifying with this GPGStrategy.
267
335
:param command_line_input: comma separated list of patterns from
272
acceptable_keys_config = self._config.acceptable_keys()
274
if isinstance(acceptable_keys_config, unicode):
275
acceptable_keys_config = str(acceptable_keys_config)
276
except UnicodeEncodeError:
277
raise errors.BzrCommandError('Only ASCII permitted in option names')
340
acceptable_keys_config = self._config_stack.get('acceptable_keys')
279
341
if acceptable_keys_config is not None:
280
key_patterns = acceptable_keys_config
281
if command_line_input is not None: #command line overrides config
282
key_patterns = command_line_input
283
if key_patterns is not None:
284
patterns = key_patterns.split(",")
342
patterns = acceptable_keys_config
343
if command_line_input is not None: # command line overrides config
344
patterns = command_line_input.split(',')
286
347
self.acceptable_keys = []
287
348
for pattern in patterns:
288
349
result = self.context.keylist(pattern)
292
353
self.acceptable_keys.append(key.subkeys[0].fpr)
293
354
trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
294
355
if not found_key:
295
trace.note(i18n.gettext(
296
"No GnuPG key results for pattern: {}"
357
"No GnuPG key results for pattern: {0}"
297
358
).format(pattern))
299
def do_verifications(self, revisions, repository):
360
@deprecated_method(deprecated_in((2, 6, 0)))
361
def do_verifications(self, revisions, repository,
362
process_events_callback=None):
300
363
"""do verifications on a set of revisions
302
365
:param revisions: list of revision ids to verify
303
366
:param repository: repository object
367
:param process_events_callback: method to call for GUI frontends that
368
want to keep their UI refreshed
305
370
:return: count dictionary of results of each type,
306
371
result list for each revision,
307
372
boolean True if all results are verified successfully
309
count = {SIGNATURE_VALID: 0,
310
SIGNATURE_KEY_MISSING: 0,
311
SIGNATURE_NOT_VALID: 0,
312
SIGNATURE_NOT_SIGNED: 0}
314
all_verifiable = True
315
for rev_id in revisions:
316
verification_result, uid =\
317
repository.verify_revision(rev_id,self)
318
result.append([rev_id, verification_result, uid])
319
count[verification_result] += 1
320
if verification_result != SIGNATURE_VALID:
321
all_verifiable = False
322
return (count, result, all_verifiable)
374
return bulk_verify_signatures(repository, revisions, self,
375
process_events_callback)
377
@deprecated_method(deprecated_in((2, 6, 0)))
324
378
def verbose_valid_message(self, result):
325
379
"""takes a verify result and returns list of signed commits strings"""
327
for rev_id, validity, uid in result:
328
if validity == SIGNATURE_VALID:
329
signers.setdefault(uid, 0)
332
for uid, number in signers.items():
333
result.append( i18n.ngettext("{0} signed {1} commit",
334
"{0} signed {1} commits",
335
number).format(uid, number) )
380
return verbose_valid_message(result)
382
@deprecated_method(deprecated_in((2, 6, 0)))
339
383
def verbose_not_valid_message(self, result, repo):
340
384
"""takes a verify result and returns list of not valid commit info"""
342
for rev_id, validity, empty in result:
343
if validity == SIGNATURE_NOT_VALID:
344
revision = repo.get_revision(rev_id)
345
authors = ', '.join(revision.get_apparent_authors())
346
signers.setdefault(authors, 0)
347
signers[authors] += 1
349
for authors, number in signers.items():
350
result.append( i18n.ngettext("{0} commit by author {1}",
351
"{0} commits by author {1}",
352
number).format(number, authors) )
385
return verbose_not_valid_message(result, repo)
387
@deprecated_method(deprecated_in((2, 6, 0)))
355
388
def verbose_not_signed_message(self, result, repo):
356
389
"""takes a verify result and returns list of not signed commit info"""
358
for rev_id, validity, empty in result:
359
if validity == SIGNATURE_NOT_SIGNED:
360
revision = repo.get_revision(rev_id)
361
authors = ', '.join(revision.get_apparent_authors())
362
signers.setdefault(authors, 0)
363
signers[authors] += 1
365
for authors, number in signers.items():
366
result.append( i18n.ngettext("{0} commit by author {1}",
367
"{0} commits by author {1}",
368
number).format(number, authors) )
390
return verbose_not_valid_message(result, repo)
392
@deprecated_method(deprecated_in((2, 6, 0)))
371
393
def verbose_missing_key_message(self, result):
372
394
"""takes a verify result and returns list of missing key info"""
374
for rev_id, validity, fingerprint in result:
375
if validity == SIGNATURE_KEY_MISSING:
376
signers.setdefault(fingerprint, 0)
377
signers[fingerprint] += 1
379
for fingerprint, number in signers.items():
380
result.append( i18n.ngettext("Unknown key {0} signed {1} commit",
381
"Unknown key {0} signed {1} commits",
382
number).format(fingerprint, number) )
395
return verbose_missing_key_message(result)
397
@deprecated_method(deprecated_in((2, 6, 0)))
398
def verbose_expired_key_message(self, result, repo):
399
"""takes a verify result and returns list of expired key info"""
400
return verbose_expired_key_message(result, repo)
402
@deprecated_method(deprecated_in((2, 6, 0)))
385
403
def valid_commits_message(self, count):
386
404
"""returns message for number of commits"""
387
return i18n.gettext("{0} commits with valid signatures").format(
388
count[SIGNATURE_VALID])
405
return valid_commits_message(count)
407
@deprecated_method(deprecated_in((2, 6, 0)))
390
408
def unknown_key_message(self, count):
391
409
"""returns message for number of commits"""
392
return i18n.ngettext("{0} commit with unknown key",
393
"{0} commits with unknown keys",
394
count[SIGNATURE_KEY_MISSING]).format(
395
count[SIGNATURE_KEY_MISSING])
410
return unknown_key_message(count)
412
@deprecated_method(deprecated_in((2, 6, 0)))
397
413
def commit_not_valid_message(self, count):
398
414
"""returns message for number of commits"""
399
return i18n.ngettext("{0} commit not valid",
400
"{0} commits not valid",
401
count[SIGNATURE_NOT_VALID]).format(
402
count[SIGNATURE_NOT_VALID])
415
return commit_not_valid_message(count)
417
@deprecated_method(deprecated_in((2, 6, 0)))
404
418
def commit_not_signed_message(self, count):
405
419
"""returns message for number of commits"""
406
return i18n.ngettext("{0} commit not signed",
407
"{0} commits not signed",
408
count[SIGNATURE_NOT_SIGNED]).format(
409
count[SIGNATURE_NOT_SIGNED])
420
return commit_not_signed_message(count)
422
@deprecated_method(deprecated_in((2, 6, 0)))
423
def expired_commit_message(self, count):
424
"""returns message for number of commits"""
425
return expired_commit_message(count)
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])
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])
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])
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])
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])
466
def verbose_expired_key_message(result, repo):
467
"""takes a verify result and returns list of expired key info"""
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
478
for fingerprint, number in signers.items():
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",
483
number, fingerprint_to_authors[fingerprint], fingerprint))
487
def verbose_valid_message(result):
488
"""takes a verify result and returns list of signed commits strings"""
490
for rev_id, validity, uid in result:
491
if validity == SIGNATURE_VALID:
492
signers.setdefault(uid, 0)
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))
502
def verbose_not_valid_message(result, repo):
503
"""takes a verify result and returns list of not valid commit info"""
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
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))
519
def verbose_not_signed_message(result, repo):
520
"""takes a verify result and returns list of not signed commit info"""
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
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))
536
def verbose_missing_key_message(result):
537
"""takes a verify result and returns list of missing key info"""
539
for rev_id, validity, fingerprint in result:
540
if validity == SIGNATURE_KEY_MISSING:
541
signers.setdefault(fingerprint, 0)
542
signers[fingerprint] += 1
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))