116
121
return (count, result, all_verifiable)
118
123
def valid_commits_message(self, count):
119
return gettext(u"{0} commits with valid signatures").format(
120
count[SIGNATURE_VALID])
124
return i18n.gettext(u"{0} commits with valid signatures").format(
125
count[SIGNATURE_VALID])
122
127
def unknown_key_message(self, count):
123
return ngettext(u"{0} commit with unknown key",
128
return i18n.ngettext(u"{0} commit with unknown key",
124
129
u"{0} commits with unknown keys",
125
130
count[SIGNATURE_KEY_MISSING]).format(
126
131
count[SIGNATURE_KEY_MISSING])
128
133
def commit_not_valid_message(self, count):
129
return ngettext(u"{0} commit not valid",
134
return i18n.ngettext(u"{0} commit not valid",
130
135
u"{0} commits not valid",
131
136
count[SIGNATURE_NOT_VALID]).format(
132
137
count[SIGNATURE_NOT_VALID])
134
139
def commit_not_signed_message(self, count):
135
return ngettext(u"{0} commit not signed",
140
return i18n.ngettext(u"{0} commit not signed",
136
141
u"{0} commits not signed",
137
142
count[SIGNATURE_NOT_SIGNED]).format(
138
143
count[SIGNATURE_NOT_SIGNED])
140
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])
147
146
def _set_gpg_tty():
148
147
tty = os.environ.get('TTY')
186
177
def _command_line(self):
187
key = self._config_stack.get('gpg_signing_key')
188
if key is None or key == 'default':
189
# 'default' or not setting gpg_signing_key at all means we should
190
# use the user email address
191
key = config.extract_email_address(self._config_stack.get('email'))
192
return [self._config_stack.get('gpg_signing_command'), '--clearsign',
178
return [self._config.gpg_signing_command(), '--clearsign']
180
def __init__(self, config):
181
self._config = config
184
self.context = gpgme.Context()
185
except ImportError, error:
186
pass # can't use verify()
195
188
def sign(self, content):
196
189
if isinstance(content, unicode):
244
237
signature = StringIO(content)
245
238
plain_output = StringIO()
247
241
result = self.context.verify(signature, None, plain_output)
248
242
except gpgme.GpgmeError,error:
249
243
raise errors.SignatureVerificationFailed(error[2])
251
# No result if input is invalid.
252
# test_verify_invalid()
253
245
if len(result) == 0:
254
246
return SIGNATURE_NOT_VALID, None
255
# User has specified a list of acceptable keys, check our result is in
256
# it. test_verify_unacceptable_key()
257
247
fingerprint = result[0].fpr
258
248
if self.acceptable_keys is not None:
259
249
if not fingerprint in self.acceptable_keys:
260
250
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
261
# Check the signature actually matches the testament.
262
# test_verify_bad_testament()
263
251
if testament != plain_output.getvalue():
264
252
return SIGNATURE_NOT_VALID, None
265
# Yay gpgme set the valid bit.
266
# Can't write a test for this one as you can't set a key to be
267
# trusted using gpgme.
268
253
if result[0].summary & gpgme.SIGSUM_VALID:
269
254
key = self.context.get_key(fingerprint)
270
255
name = key.uids[0].name
271
256
email = key.uids[0].email
272
257
return SIGNATURE_VALID, name + " <" + email + ">"
273
# Sigsum_red indicates a problem, unfortunatly I have not been able
274
# to write any tests which actually set this.
275
258
if result[0].summary & gpgme.SIGSUM_RED:
276
259
return SIGNATURE_NOT_VALID, None
277
# GPG does not know this key.
278
# test_verify_unknown_key()
279
260
if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
280
261
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
281
# Summary isn't set if sig is valid but key is untrusted but if user
282
# has explicity set the key as acceptable we can validate it.
262
#summary isn't set if sig is valid but key is untrusted
283
263
if result[0].summary == 0 and self.acceptable_keys is not None:
284
264
if fingerprint in self.acceptable_keys:
285
# test_verify_untrusted_but_accepted()
286
265
return SIGNATURE_VALID, None
287
# test_verify_valid_but_untrusted()
288
if result[0].summary == 0 and self.acceptable_keys is None:
289
return SIGNATURE_NOT_VALID, None
290
if result[0].summary & gpgme.SIGSUM_KEY_EXPIRED:
291
expires = self.context.get_key(result[0].fpr).subkeys[0].expires
292
if expires > result[0].timestamp:
293
# The expired key was not expired at time of signing.
294
# test_verify_expired_but_valid()
295
return SIGNATURE_EXPIRED, fingerprint[-8:]
297
# I can't work out how to create a test where the signature
298
# was expired at the time of signing.
299
return SIGNATURE_NOT_VALID, None
300
# A signature from a revoked key gets this.
301
# test_verify_revoked_signature()
302
if result[0].summary & gpgme.SIGSUM_SYS_ERROR:
303
return SIGNATURE_NOT_VALID, None
304
# Other error types such as revoked keys should (I think) be caught by
305
# SIGSUM_RED so anything else means something is buggy.
267
return SIGNATURE_KEY_MISSING, None
306
268
raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
307
269
"verification result")
309
271
def set_acceptable_keys(self, command_line_input):
310
"""Set the acceptable keys for verifying with this GPGStrategy.
272
"""sets the acceptable keys for verifying with this GPGStrategy
312
274
:param command_line_input: comma separated list of patterns from
316
278
key_patterns = None
317
acceptable_keys_config = self._config_stack.get('acceptable_keys')
279
acceptable_keys_config = self._config.acceptable_keys()
319
281
if isinstance(acceptable_keys_config, unicode):
320
282
acceptable_keys_config = str(acceptable_keys_config)
321
283
except UnicodeEncodeError:
322
# gpg Context.keylist(pattern) does not like unicode
323
raise errors.BzrCommandError(
324
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')
326
287
if acceptable_keys_config is not None:
327
288
key_patterns = acceptable_keys_config
328
if command_line_input is not None: # command line overrides config
289
if command_line_input is not None: #command line overrides config
329
290
key_patterns = command_line_input
330
291
if key_patterns is not None:
331
292
patterns = key_patterns.split(",")
430
390
signers[fingerprint] += 1
432
392
for fingerprint, number in signers.items():
433
result.append( ngettext(u"Unknown key {0} signed {1} commit",
393
result.append( i18n.ngettext(u"Unknown key {0} signed {1} commit",
434
394
u"Unknown key {0} signed {1} commits",
435
395
number).format(fingerprint, number) )
438
def verbose_expired_key_message(self, result, repo):
439
"""takes a verify result and returns list of expired key info"""
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
450
for fingerprint, number in signers.items():
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",
455
number, fingerprint_to_authors[fingerprint], fingerprint) )
458
398
def valid_commits_message(self, count):
459
399
"""returns message for number of commits"""
460
return gettext(u"{0} commits with valid signatures").format(
400
return i18n.gettext(u"{0} commits with valid signatures").format(
461
401
count[SIGNATURE_VALID])
463
403
def unknown_key_message(self, count):
464
404
"""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(
405
return i18n.ngettext(u"{0} commit with unknown key",
406
u"{0} commits with unknown keys",
407
count[SIGNATURE_KEY_MISSING]).format(
468
408
count[SIGNATURE_KEY_MISSING])
470
410
def commit_not_valid_message(self, count):
471
411
"""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(
412
return i18n.ngettext(u"{0} commit not valid",
413
u"{0} commits not valid",
414
count[SIGNATURE_NOT_VALID]).format(
475
415
count[SIGNATURE_NOT_VALID])
477
417
def commit_not_signed_message(self, count):
478
418
"""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(
419
return i18n.ngettext(u"{0} commit not signed",
420
u"{0} commits not signed",
421
count[SIGNATURE_NOT_SIGNED]).format(
482
422
count[SIGNATURE_NOT_SIGNED])
484
def expired_commit_message(self, count):
485
"""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])