89
53
return ("-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content +
90
54
"-----END PSEUDO-SIGNED CONTENT-----\n")
92
def verify(self, content, testament):
93
return SIGNATURE_VALID, None
95
def set_acceptable_keys(self, command_line_input):
96
if command_line_input is not None:
97
patterns = command_line_input.split(",")
98
self.acceptable_keys = []
99
for pattern in patterns:
100
if pattern == "unknown":
103
self.acceptable_keys.append(pattern)
105
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)
121
def valid_commits_message(self, count):
122
return i18n.gettext("{0} commits with valid signatures").format(
123
count[SIGNATURE_VALID])
125
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])
131
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])
137
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])
144
57
def _set_gpg_tty():
145
58
tty = os.environ.get('TTY')
213
111
raise errors.SigningFailed(self._command_line())
217
def verify(self, content, testament):
218
"""Check content has a valid signature.
220
:param content: the commit signature
221
:param testament: the valid testament string for the commit
223
:return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid
227
except ImportError, error:
228
raise errors.GpgmeNotInstalled(error)
230
signature = StringIO(content)
231
plain_output = StringIO()
234
result = self.context.verify(signature, None, plain_output)
235
except gpgme.GpgmeError,error:
236
raise errors.SignatureVerificationFailed(error[2])
239
return SIGNATURE_NOT_VALID, None
240
fingerprint = result[0].fpr
241
if self.acceptable_keys is not None:
242
if not fingerprint in self.acceptable_keys:
243
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
244
if testament != plain_output.getvalue():
245
return SIGNATURE_NOT_VALID, None
246
if result[0].summary & gpgme.SIGSUM_VALID:
247
key = self.context.get_key(fingerprint)
248
name = key.uids[0].name
249
email = key.uids[0].email
250
return SIGNATURE_VALID, name + " <" + email + ">"
251
if result[0].summary & gpgme.SIGSUM_RED:
252
return SIGNATURE_NOT_VALID, None
253
if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
254
return SIGNATURE_KEY_MISSING, fingerprint[-8:]
255
#summary isn't set if sig is valid but key is untrusted
256
if result[0].summary == 0 and self.acceptable_keys is not None:
257
if fingerprint in self.acceptable_keys:
258
return SIGNATURE_VALID, None
260
return SIGNATURE_KEY_MISSING, None
261
raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
262
"verification result")
264
def set_acceptable_keys(self, command_line_input):
265
"""sets the acceptable keys for verifying with this GPGStrategy
267
: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')
279
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(",")
286
self.acceptable_keys = []
287
for pattern in patterns:
288
result = self.context.keylist(pattern)
292
self.acceptable_keys.append(key.subkeys[0].fpr)
293
trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
295
trace.note(i18n.gettext(
296
"No GnuPG key results for pattern: {}"
299
def do_verifications(self, revisions, repository):
300
"""do verifications on a set of revisions
302
:param revisions: list of revision ids to verify
303
:param repository: repository object
305
:return: count dictionary of results of each type,
306
result list for each revision,
307
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)
324
def verbose_valid_message(self, result):
325
"""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) )
339
def verbose_not_valid_message(self, result, repo):
340
"""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) )
355
def verbose_not_signed_message(self, result, repo):
356
"""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) )
371
def verbose_missing_key_message(self, result):
372
"""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) )
385
def valid_commits_message(self, count):
386
"""returns message for number of commits"""
387
return i18n.gettext("{0} commits with valid signatures").format(
388
count[SIGNATURE_VALID])
390
def unknown_key_message(self, count):
391
"""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])
397
def commit_not_valid_message(self, count):
398
"""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])
404
def commit_not_signed_message(self, count):
405
"""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])