143
105
self.acceptable_keys.append(pattern)
145
@deprecated_method(deprecated_in((2, 6, 0)))
146
107
def do_verifications(self, revisions, repository):
147
return bulk_verify_signatures(repository, revisions, self)
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)
149
@deprecated_method(deprecated_in((2, 6, 0)))
150
123
def valid_commits_message(self, count):
151
return valid_commits_message(count)
124
return i18n.gettext(u"{0} commits with valid signatures").format(
125
count[SIGNATURE_VALID])
153
@deprecated_method(deprecated_in((2, 6, 0)))
154
127
def unknown_key_message(self, count):
155
return unknown_key_message(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])
157
@deprecated_method(deprecated_in((2, 6, 0)))
158
133
def commit_not_valid_message(self, count):
159
return commit_not_valid_message(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])
161
@deprecated_method(deprecated_in((2, 6, 0)))
162
139
def commit_not_signed_message(self, count):
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)
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])
170
146
def _set_gpg_tty():
267
237
signature = StringIO(content)
268
238
plain_output = StringIO()
270
241
result = self.context.verify(signature, None, plain_output)
271
242
except gpgme.GpgmeError,error:
272
243
raise errors.SignatureVerificationFailed(error[2])
274
# No result if input is invalid.
275
# test_verify_invalid()
276
245
if len(result) == 0:
277
246
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()
280
247
fingerprint = result[0].fpr
281
248
if self.acceptable_keys is not None:
282
249
if not fingerprint in self.acceptable_keys:
283
250
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
284
# Check the signature actually matches the testament.
285
# test_verify_bad_testament()
286
251
if testament != plain_output.getvalue():
287
252
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.
291
253
if result[0].summary & gpgme.SIGSUM_VALID:
292
254
key = self.context.get_key(fingerprint)
293
255
name = key.uids[0].name
294
256
email = key.uids[0].email
295
257
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.
298
258
if result[0].summary & gpgme.SIGSUM_RED:
299
259
return SIGNATURE_NOT_VALID, None
300
# GPG does not know this key.
301
# test_verify_unknown_key()
302
260
if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
303
261
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
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.
262
#summary isn't set if sig is valid but key is untrusted
306
263
if result[0].summary == 0 and self.acceptable_keys is not None:
307
264
if fingerprint in self.acceptable_keys:
308
# test_verify_untrusted_but_accepted()
309
265
return SIGNATURE_VALID, 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.
267
return SIGNATURE_KEY_MISSING, None
329
268
raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
330
269
"verification result")
332
271
def set_acceptable_keys(self, command_line_input):
333
"""Set the acceptable keys for verifying with this GPGStrategy.
272
"""sets the acceptable keys for verifying with this GPGStrategy
335
274
:param command_line_input: comma separated list of patterns from
339
278
key_patterns = None
340
acceptable_keys_config = self._config_stack.get('acceptable_keys')
279
acceptable_keys_config = self._config.acceptable_keys()
342
281
if isinstance(acceptable_keys_config, unicode):
343
282
acceptable_keys_config = str(acceptable_keys_config)
344
283
except UnicodeEncodeError:
345
# gpg Context.keylist(pattern) does not like unicode
346
raise errors.BzrCommandError(
347
gettext('Only ASCII permitted in option names'))
284
#gpg Context.keylist(pattern) does not like unicode
285
raise errors.BzrCommandError('Only ASCII permitted in option names')
349
287
if acceptable_keys_config is not None:
350
288
key_patterns = acceptable_keys_config
351
if command_line_input is not None: # command line overrides config
289
if command_line_input is not None: #command line overrides config
352
290
key_patterns = command_line_input
353
291
if key_patterns is not None:
354
292
patterns = key_patterns.split(",")
362
300
self.acceptable_keys.append(key.subkeys[0].fpr)
363
301
trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
364
302
if not found_key:
366
"No GnuPG key results for pattern: {0}"
303
trace.note(i18n.gettext(
304
"No GnuPG key results for pattern: {}"
367
305
).format(pattern))
369
@deprecated_method(deprecated_in((2, 6, 0)))
370
307
def do_verifications(self, revisions, repository,
371
308
process_events_callback=None):
372
309
"""do verifications on a set of revisions
374
311
:param revisions: list of revision ids to verify
375
312
:param repository: repository object
376
313
:param process_events_callback: method to call for GUI frontends that
377
want to keep their UI refreshed
314
want to keep their UI refreshed
379
316
:return: count dictionary of results of each type,
380
317
result list for each revision,
381
318
boolean True if all results are verified successfully
383
return bulk_verify_signatures(repository, revisions, self,
384
process_events_callback)
320
count = {SIGNATURE_VALID: 0,
321
SIGNATURE_KEY_MISSING: 0,
322
SIGNATURE_NOT_VALID: 0,
323
SIGNATURE_NOT_SIGNED: 0}
325
all_verifiable = True
326
for rev_id in revisions:
327
verification_result, uid =\
328
repository.verify_revision(rev_id,self)
329
result.append([rev_id, verification_result, uid])
330
count[verification_result] += 1
331
if verification_result != SIGNATURE_VALID:
332
all_verifiable = False
333
if process_events_callback is not None:
334
process_events_callback()
335
return (count, result, all_verifiable)
386
@deprecated_method(deprecated_in((2, 6, 0)))
387
337
def verbose_valid_message(self, result):
388
338
"""takes a verify result and returns list of signed commits strings"""
389
return verbose_valid_message(result)
391
@deprecated_method(deprecated_in((2, 6, 0)))
340
for rev_id, validity, uid in result:
341
if validity == SIGNATURE_VALID:
342
signers.setdefault(uid, 0)
345
for uid, number in signers.items():
346
result.append( i18n.ngettext(u"{0} signed {1} commit",
347
u"{0} signed {1} commits",
348
number).format(uid, number) )
392
352
def verbose_not_valid_message(self, result, repo):
393
353
"""takes a verify result and returns list of not valid commit info"""
394
return verbose_not_valid_message(result, repo)
355
for rev_id, validity, empty in result:
356
if validity == SIGNATURE_NOT_VALID:
357
revision = repo.get_revision(rev_id)
358
authors = ', '.join(revision.get_apparent_authors())
359
signers.setdefault(authors, 0)
360
signers[authors] += 1
362
for authors, number in signers.items():
363
result.append( i18n.ngettext(u"{0} commit by author {1}",
364
u"{0} commits by author {1}",
365
number).format(number, authors) )
396
@deprecated_method(deprecated_in((2, 6, 0)))
397
368
def verbose_not_signed_message(self, result, repo):
398
369
"""takes a verify result and returns list of not signed commit info"""
399
return verbose_not_valid_message(result, repo)
371
for rev_id, validity, empty in result:
372
if validity == SIGNATURE_NOT_SIGNED:
373
revision = repo.get_revision(rev_id)
374
authors = ', '.join(revision.get_apparent_authors())
375
signers.setdefault(authors, 0)
376
signers[authors] += 1
378
for authors, number in signers.items():
379
result.append( i18n.ngettext(u"{0} commit by author {1}",
380
u"{0} commits by author {1}",
381
number).format(number, authors) )
401
@deprecated_method(deprecated_in((2, 6, 0)))
402
384
def verbose_missing_key_message(self, result):
403
385
"""takes a verify result and returns list of missing key info"""
404
return verbose_missing_key_message(result)
406
@deprecated_method(deprecated_in((2, 6, 0)))
407
def verbose_expired_key_message(self, result, repo):
408
"""takes a verify result and returns list of expired key info"""
409
return verbose_expired_key_message(result, repo)
411
@deprecated_method(deprecated_in((2, 6, 0)))
387
for rev_id, validity, fingerprint in result:
388
if validity == SIGNATURE_KEY_MISSING:
389
signers.setdefault(fingerprint, 0)
390
signers[fingerprint] += 1
392
for fingerprint, number in signers.items():
393
result.append( i18n.ngettext(u"Unknown key {0} signed {1} commit",
394
u"Unknown key {0} signed {1} commits",
395
number).format(fingerprint, number) )
412
398
def valid_commits_message(self, count):
413
399
"""returns message for number of commits"""
414
return valid_commits_message(count)
400
return i18n.gettext(u"{0} commits with valid signatures").format(
401
count[SIGNATURE_VALID])
416
@deprecated_method(deprecated_in((2, 6, 0)))
417
403
def unknown_key_message(self, count):
418
404
"""returns message for number of commits"""
419
return unknown_key_message(count)
405
return i18n.ngettext(u"{0} commit with unknown key",
406
u"{0} commits with unknown keys",
407
count[SIGNATURE_KEY_MISSING]).format(
408
count[SIGNATURE_KEY_MISSING])
421
@deprecated_method(deprecated_in((2, 6, 0)))
422
410
def commit_not_valid_message(self, count):
423
411
"""returns message for number of commits"""
424
return commit_not_valid_message(count)
412
return i18n.ngettext(u"{0} commit not valid",
413
u"{0} commits not valid",
414
count[SIGNATURE_NOT_VALID]).format(
415
count[SIGNATURE_NOT_VALID])
426
@deprecated_method(deprecated_in((2, 6, 0)))
427
417
def commit_not_signed_message(self, count):
428
418
"""returns message for number of commits"""
429
return commit_not_signed_message(count)
431
@deprecated_method(deprecated_in((2, 6, 0)))
432
def expired_commit_message(self, count):
433
"""returns message for number of commits"""
434
return expired_commit_message(count)
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])
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])
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])
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])
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])
475
def verbose_expired_key_message(result, repo):
476
"""takes a verify result and returns list of expired key info"""
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
487
for fingerprint, number in signers.items():
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",
492
number, fingerprint_to_authors[fingerprint], fingerprint))
496
def verbose_valid_message(result):
497
"""takes a verify result and returns list of signed commits strings"""
499
for rev_id, validity, uid in result:
500
if validity == SIGNATURE_VALID:
501
signers.setdefault(uid, 0)
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))
511
def verbose_not_valid_message(result, repo):
512
"""takes a verify result and returns list of not valid commit info"""
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
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))
528
def verbose_not_signed_message(result, repo):
529
"""takes a verify result and returns list of not signed commit info"""
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
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))
545
def verbose_missing_key_message(result):
546
"""takes a verify result and returns list of missing key info"""
548
for rev_id, validity, fingerprint in result:
549
if validity == SIGNATURE_KEY_MISSING:
550
signers.setdefault(fingerprint, 0)
551
signers[fingerprint] += 1
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))
419
return i18n.ngettext(u"{0} commit not signed",
420
u"{0} commits not signed",
421
count[SIGNATURE_NOT_SIGNED]).format(
422
count[SIGNATURE_NOT_SIGNED])