105
143
self.acceptable_keys.append(pattern)
145
@deprecated_method(deprecated_in((2, 6, 0)))
107
146
def do_verifications(self, revisions, repository):
108
count = {SIGNATURE_VALID: 0,
109
SIGNATURE_KEY_MISSING: 0,
110
SIGNATURE_NOT_VALID: 0,
111
SIGNATURE_NOT_SIGNED: 0}
113
all_verifiable = True
114
for rev_id in revisions:
115
verification_result, uid =\
116
repository.verify_revision(rev_id,self)
117
result.append([rev_id, verification_result, uid])
118
count[verification_result] += 1
119
if verification_result != SIGNATURE_VALID:
120
all_verifiable = False
121
return (count, result, all_verifiable)
147
return bulk_verify_signatures(repository, revisions, self)
149
@deprecated_method(deprecated_in((2, 6, 0)))
123
150
def valid_commits_message(self, count):
124
return i18n.gettext(u"{0} commits with valid signatures").format(
125
count[SIGNATURE_VALID])
151
return valid_commits_message(count)
153
@deprecated_method(deprecated_in((2, 6, 0)))
127
154
def unknown_key_message(self, count):
128
return i18n.ngettext(u"{0} commit with unknown key",
129
u"{0} commits with unknown keys",
130
count[SIGNATURE_KEY_MISSING]).format(
131
count[SIGNATURE_KEY_MISSING])
155
return unknown_key_message(count)
157
@deprecated_method(deprecated_in((2, 6, 0)))
133
158
def commit_not_valid_message(self, count):
134
return i18n.ngettext(u"{0} commit not valid",
135
u"{0} commits not valid",
136
count[SIGNATURE_NOT_VALID]).format(
137
count[SIGNATURE_NOT_VALID])
159
return commit_not_valid_message(count)
161
@deprecated_method(deprecated_in((2, 6, 0)))
139
162
def commit_not_signed_message(self, count):
140
return i18n.ngettext(u"{0} commit not signed",
141
u"{0} commits not signed",
142
count[SIGNATURE_NOT_SIGNED]).format(
143
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)
146
170
def _set_gpg_tty():
239
267
signature = StringIO(content)
240
268
plain_output = StringIO()
243
270
result = self.context.verify(signature, None, plain_output)
244
271
except gpgme.GpgmeError,error:
245
272
raise errors.SignatureVerificationFailed(error[2])
274
# No result if input is invalid.
275
# test_verify_invalid()
247
276
if len(result) == 0:
248
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()
249
280
fingerprint = result[0].fpr
250
281
if self.acceptable_keys is not None:
251
282
if not fingerprint in self.acceptable_keys:
252
283
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
284
# Check the signature actually matches the testament.
285
# test_verify_bad_testament()
253
286
if testament != plain_output.getvalue():
254
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.
255
291
if result[0].summary & gpgme.SIGSUM_VALID:
256
292
key = self.context.get_key(fingerprint)
257
293
name = key.uids[0].name
258
294
email = key.uids[0].email
259
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.
260
298
if result[0].summary & gpgme.SIGSUM_RED:
261
299
return SIGNATURE_NOT_VALID, None
300
# GPG does not know this key.
301
# test_verify_unknown_key()
262
302
if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
263
303
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
264
#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.
265
306
if result[0].summary == 0 and self.acceptable_keys is not None:
266
307
if fingerprint in self.acceptable_keys:
308
# test_verify_untrusted_but_accepted()
267
309
return SIGNATURE_VALID, None
269
return SIGNATURE_KEY_MISSING, None
270
raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
271
"verification result")
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
or result[0].status.strerror == 'Certificate revoked')):
327
return SIGNATURE_NOT_VALID, None
328
# Other error types such as revoked keys should (I think) be caught by
329
# SIGSUM_RED so anything else means something is buggy.
330
raise errors.SignatureVerificationFailed(
331
"Unknown GnuPG key verification result")
273
333
def set_acceptable_keys(self, command_line_input):
274
"""sets the acceptable keys for verifying with this GPGStrategy
334
"""Set the acceptable keys for verifying with this GPGStrategy.
276
336
:param command_line_input: comma separated list of patterns from
281
acceptable_keys_config = self._config.acceptable_keys()
283
if isinstance(acceptable_keys_config, unicode):
284
acceptable_keys_config = str(acceptable_keys_config)
285
except UnicodeEncodeError:
286
#gpg Context.keylist(pattern) does not like unicode
287
raise errors.BzrCommandError('Only ASCII permitted in option names')
341
acceptable_keys_config = self._config_stack.get('acceptable_keys')
289
342
if acceptable_keys_config is not None:
290
key_patterns = acceptable_keys_config
291
if command_line_input is not None: #command line overrides config
292
key_patterns = command_line_input
293
if key_patterns is not None:
294
patterns = key_patterns.split(",")
343
patterns = acceptable_keys_config
344
if command_line_input is not None: # command line overrides config
345
patterns = command_line_input.split(',')
296
348
self.acceptable_keys = []
297
349
for pattern in patterns:
298
350
result = self.context.keylist(pattern)
302
354
self.acceptable_keys.append(key.subkeys[0].fpr)
303
355
trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
304
356
if not found_key:
305
trace.note(i18n.gettext(
306
"No GnuPG key results for pattern: {}"
358
"No GnuPG key results for pattern: {0}"
307
359
).format(pattern))
361
@deprecated_method(deprecated_in((2, 6, 0)))
309
362
def do_verifications(self, revisions, repository,
310
363
process_events_callback=None):
311
364
"""do verifications on a set of revisions
313
366
:param revisions: list of revision ids to verify
314
367
:param repository: repository object
315
368
:param process_events_callback: method to call for GUI frontends that
316
want to keep their UI refreshed
369
want to keep their UI refreshed
318
371
:return: count dictionary of results of each type,
319
372
result list for each revision,
320
373
boolean True if all results are verified successfully
322
count = {SIGNATURE_VALID: 0,
323
SIGNATURE_KEY_MISSING: 0,
324
SIGNATURE_NOT_VALID: 0,
325
SIGNATURE_NOT_SIGNED: 0}
327
all_verifiable = True
328
for rev_id in revisions:
329
verification_result, uid =\
330
repository.verify_revision(rev_id,self)
331
result.append([rev_id, verification_result, uid])
332
count[verification_result] += 1
333
if verification_result != SIGNATURE_VALID:
334
all_verifiable = False
335
if process_events_callback is not None:
336
process_events_callback()
337
return (count, result, all_verifiable)
375
return bulk_verify_signatures(repository, revisions, self,
376
process_events_callback)
378
@deprecated_method(deprecated_in((2, 6, 0)))
339
379
def verbose_valid_message(self, result):
340
380
"""takes a verify result and returns list of signed commits strings"""
342
for rev_id, validity, uid in result:
343
if validity == SIGNATURE_VALID:
344
signers.setdefault(uid, 0)
347
for uid, number in signers.items():
348
result.append( i18n.ngettext(u"{0} signed {1} commit",
349
u"{0} signed {1} commits",
350
number).format(uid, number) )
381
return verbose_valid_message(result)
383
@deprecated_method(deprecated_in((2, 6, 0)))
354
384
def verbose_not_valid_message(self, result, repo):
355
385
"""takes a verify result and returns list of not valid commit info"""
357
for rev_id, validity, empty in result:
358
if validity == SIGNATURE_NOT_VALID:
359
revision = repo.get_revision(rev_id)
360
authors = ', '.join(revision.get_apparent_authors())
361
signers.setdefault(authors, 0)
362
signers[authors] += 1
364
for authors, number in signers.items():
365
result.append( i18n.ngettext(u"{0} commit by author {1}",
366
u"{0} commits by author {1}",
367
number).format(number, authors) )
386
return verbose_not_valid_message(result, repo)
388
@deprecated_method(deprecated_in((2, 6, 0)))
370
389
def verbose_not_signed_message(self, result, repo):
371
390
"""takes a verify result and returns list of not signed commit info"""
373
for rev_id, validity, empty in result:
374
if validity == SIGNATURE_NOT_SIGNED:
375
revision = repo.get_revision(rev_id)
376
authors = ', '.join(revision.get_apparent_authors())
377
signers.setdefault(authors, 0)
378
signers[authors] += 1
380
for authors, number in signers.items():
381
result.append( i18n.ngettext(u"{0} commit by author {1}",
382
u"{0} commits by author {1}",
383
number).format(number, authors) )
391
return verbose_not_valid_message(result, repo)
393
@deprecated_method(deprecated_in((2, 6, 0)))
386
394
def verbose_missing_key_message(self, result):
387
395
"""takes a verify result and returns list of missing key info"""
389
for rev_id, validity, fingerprint in result:
390
if validity == SIGNATURE_KEY_MISSING:
391
signers.setdefault(fingerprint, 0)
392
signers[fingerprint] += 1
394
for fingerprint, number in signers.items():
395
result.append( i18n.ngettext(u"Unknown key {0} signed {1} commit",
396
u"Unknown key {0} signed {1} commits",
397
number).format(fingerprint, number) )
396
return verbose_missing_key_message(result)
398
@deprecated_method(deprecated_in((2, 6, 0)))
399
def verbose_expired_key_message(self, result, repo):
400
"""takes a verify result and returns list of expired key info"""
401
return verbose_expired_key_message(result, repo)
403
@deprecated_method(deprecated_in((2, 6, 0)))
400
404
def valid_commits_message(self, count):
401
405
"""returns message for number of commits"""
402
return i18n.gettext(u"{0} commits with valid signatures").format(
403
count[SIGNATURE_VALID])
406
return valid_commits_message(count)
408
@deprecated_method(deprecated_in((2, 6, 0)))
405
409
def unknown_key_message(self, count):
406
410
"""returns message for number of commits"""
407
return i18n.ngettext(u"{0} commit with unknown key",
408
u"{0} commits with unknown keys",
409
count[SIGNATURE_KEY_MISSING]).format(
410
count[SIGNATURE_KEY_MISSING])
411
return unknown_key_message(count)
413
@deprecated_method(deprecated_in((2, 6, 0)))
412
414
def commit_not_valid_message(self, count):
413
415
"""returns message for number of commits"""
414
return i18n.ngettext(u"{0} commit not valid",
415
u"{0} commits not valid",
416
count[SIGNATURE_NOT_VALID]).format(
417
count[SIGNATURE_NOT_VALID])
416
return commit_not_valid_message(count)
418
@deprecated_method(deprecated_in((2, 6, 0)))
419
419
def commit_not_signed_message(self, count):
420
420
"""returns message for number of commits"""
421
return i18n.ngettext(u"{0} commit not signed",
422
u"{0} commits not signed",
423
count[SIGNATURE_NOT_SIGNED]).format(
424
count[SIGNATURE_NOT_SIGNED])
421
return commit_not_signed_message(count)
423
@deprecated_method(deprecated_in((2, 6, 0)))
424
def expired_commit_message(self, count):
425
"""returns message for number of commits"""
426
return expired_commit_message(count)
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])
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])
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])
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])
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])
467
def verbose_expired_key_message(result, repo):
468
"""takes a verify result and returns list of expired key info"""
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
479
for fingerprint, number in signers.items():
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",
484
number, fingerprint_to_authors[fingerprint], fingerprint))
488
def verbose_valid_message(result):
489
"""takes a verify result and returns list of signed commits strings"""
491
for rev_id, validity, uid in result:
492
if validity == SIGNATURE_VALID:
493
signers.setdefault(uid, 0)
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))
503
def verbose_not_valid_message(result, repo):
504
"""takes a verify result and returns list of not valid commit info"""
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
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))
520
def verbose_not_signed_message(result, repo):
521
"""takes a verify result and returns list of not signed commit info"""
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
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))
537
def verbose_missing_key_message(result):
538
"""takes a verify result and returns list of missing key info"""
540
for rev_id, validity, fingerprint in result:
541
if validity == SIGNATURE_KEY_MISSING:
542
signers.setdefault(fingerprint, 0)
543
signers[fingerprint] += 1
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))