Merge lp:~lifeless/launchpad/bug-830789 into lp:launchpad
- bug-830789
- Merge into devel
Proposed by
Robert Collins
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | William Grant | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 13749 | ||||
Proposed branch: | lp:~lifeless/launchpad/bug-830789 | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
858 lines (+2/-755) 7 files modified
lib/canonical/launchpad/interfaces/gpghandler.py (+0/-20) lib/canonical/launchpad/scripts/ftests/test_keyringtrustanalyser.py (+0/-292) lib/canonical/launchpad/utilities/ftests/test_gpghandler.py (+2/-52) lib/canonical/launchpad/utilities/gpghandler.py (+0/-36) lib/lp/registry/scripts/keyringtrustanalyser.py (+0/-183) scripts/find-email-clusters.py (+0/-101) scripts/merge-email-clusters.py (+0/-71) |
||||
To merge this branch: | bzr merge lp:~lifeless/launchpad/bug-830789 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+72371@code.launchpad.net |
Commit message
[r=wgrant][bug=830789] Delete unused code.
Description of the change
Unused code can go to code heaven.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/canonical/launchpad/interfaces/gpghandler.py' |
2 | --- lib/canonical/launchpad/interfaces/gpghandler.py 2011-05-30 12:45:29 +0000 |
3 | +++ lib/canonical/launchpad/interfaces/gpghandler.py 2011-08-22 01:12:25 +0000 |
4 | @@ -199,14 +199,6 @@ |
5 | :return: a `PymeKey` object for the just-generated secret key. |
6 | """ |
7 | |
8 | - def importKeyringFile(filepath): |
9 | - """Import the keyring filepath into the local key database. |
10 | - |
11 | - :param filepath: the path to a keyring to import. |
12 | - |
13 | - :returns: a list of the imported keys. |
14 | - """ |
15 | - |
16 | def encryptContent(content, fingerprint): |
17 | """Encrypt the given content for the given fingerprint. |
18 | |
19 | @@ -271,15 +263,6 @@ |
20 | :raise AssertionError: if the POST request doesn't succeed. |
21 | """ |
22 | |
23 | - def checkTrustDb(): |
24 | - """Check whether the OpenPGP trust database is up to date. |
25 | - |
26 | - The method automatically rebuild the trust values if necessary. |
27 | - |
28 | - The results will be visible in any new retrieved key objects. |
29 | - Existing key objects will not reflect the new trust value. |
30 | - """ |
31 | - |
32 | def localKeys(filter=None, secret=False): |
33 | """Return an iterator of all keys locally known about. |
34 | |
35 | @@ -340,9 +323,6 @@ |
36 | can_authenticate = Attribute( |
37 | "Whether the key can be used for authentication") |
38 | |
39 | - def setOwnerTrust(value): |
40 | - """Set the owner_trust value for this key.""" |
41 | - |
42 | def export(): |
43 | """Export the context key in ASCII-armored mode. |
44 | |
45 | |
46 | === removed file 'lib/canonical/launchpad/scripts/ftests/test_keyringtrustanalyser.py' |
47 | --- lib/canonical/launchpad/scripts/ftests/test_keyringtrustanalyser.py 2011-08-12 11:19:40 +0000 |
48 | +++ lib/canonical/launchpad/scripts/ftests/test_keyringtrustanalyser.py 1970-01-01 00:00:00 +0000 |
49 | @@ -1,292 +0,0 @@ |
50 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
51 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
52 | - |
53 | -import logging |
54 | -import unittest |
55 | - |
56 | -import gpgme |
57 | -from zope.component import getUtility |
58 | - |
59 | -from canonical.launchpad.ftests import keys_for_tests |
60 | -from canonical.launchpad.interfaces.emailaddress import ( |
61 | - EmailAddressStatus, |
62 | - IEmailAddressSet, |
63 | - ) |
64 | -from canonical.launchpad.interfaces.gpghandler import IGPGHandler |
65 | -from canonical.testing.layers import LaunchpadZopelessLayer |
66 | -from lp.registry.interfaces.person import IPersonSet |
67 | -from lp.registry.scripts.keyringtrustanalyser import ( |
68 | - addOtherKeyring, |
69 | - addTrustedKeyring, |
70 | - findEmailClusters, |
71 | - getValidUids, |
72 | - mergeClusters, |
73 | - ) |
74 | - |
75 | - |
76 | -test_fpr = 'A419AE861E88BC9E04B9C26FBA2B9389DFD20543' |
77 | -foobar_fpr = '340CA3BB270E2716C9EE0B768E7EB7086C64A8C5' |
78 | - |
79 | - |
80 | -class LogCollector(logging.Handler): |
81 | - |
82 | - def __init__(self): |
83 | - logging.Handler.__init__(self) |
84 | - self.records = [] |
85 | - |
86 | - def emit(self, record): |
87 | - self.records.append(self.format(record)) |
88 | - |
89 | - |
90 | -def setupLogger(name='test_keyringtrustanalyser'): |
91 | - """Set up the named logger to collect log messages. |
92 | - |
93 | - Returns (logger, handler) |
94 | - """ |
95 | - logger = logging.getLogger(name) |
96 | - for handler in logger.handlers[:]: |
97 | - logger.removeHandler(handler) |
98 | - handler.flush() |
99 | - handler.close() |
100 | - handler = LogCollector() |
101 | - handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s")) |
102 | - logger.addHandler(handler) |
103 | - return logger, handler |
104 | - |
105 | - |
106 | -class TestKeyringTrustAnalyser(unittest.TestCase): |
107 | - layer = LaunchpadZopelessLayer |
108 | - |
109 | - def setUp(self): |
110 | - self.gpg_handler = getUtility(IGPGHandler) |
111 | - |
112 | - def tearDown(self): |
113 | - # XXX stub 2005-10-27: this should be a zope test cleanup |
114 | - # thing per SteveA. |
115 | - self.gpg_handler.resetLocalState() |
116 | - |
117 | - def _addTrustedKeys(self): |
118 | - # Add trusted key with ULTIMATE validity. This will mark UIDs as |
119 | - # valid with a single signature, which is appropriate with the |
120 | - # small amount of test data. |
121 | - filename = keys_for_tests.test_pubkey_file_from_email( |
122 | - 'test@canonical.com') |
123 | - addTrustedKeyring(filename, gpgme.VALIDITY_ULTIMATE) |
124 | - |
125 | - def _addUntrustedKeys(self): |
126 | - for ring in keys_for_tests.test_keyrings(): |
127 | - addOtherKeyring(ring) |
128 | - |
129 | - def testAddTrustedKeyring(self): |
130 | - """Test addTrustedKeyring""" |
131 | - self._addTrustedKeys() |
132 | - |
133 | - # get key from keyring |
134 | - keys = [key for key in self.gpg_handler.localKeys() |
135 | - if key.fingerprint == test_fpr] |
136 | - self.assertEqual(len(keys), 1) |
137 | - key = keys[0] |
138 | - self.assertTrue('test@canonical.com' in key.emails) |
139 | - self.assertEqual(key.owner_trust, gpgme.VALIDITY_ULTIMATE) |
140 | - |
141 | - def testAddOtherKeyring(self): |
142 | - """Test addOtherKeyring""" |
143 | - self._addUntrustedKeys() |
144 | - fingerprints = set(key.fingerprint |
145 | - for key in self.gpg_handler.localKeys()) |
146 | - self.assertTrue(test_fpr in fingerprints) |
147 | - self.assertTrue(foobar_fpr in fingerprints) |
148 | - |
149 | - def testGetValidUids(self): |
150 | - """Test getValidUids""" |
151 | - self._addTrustedKeys() |
152 | - self._addUntrustedKeys() |
153 | - |
154 | - # calculate valid UIDs |
155 | - validuids = list(getValidUids()) |
156 | - |
157 | - # test@canonical.com's non-revoked UIDs are valid |
158 | - self.assertTrue((test_fpr, 'test@canonical.com') in validuids) |
159 | - self.assertTrue((test_fpr, |
160 | - 'sample.person@canonical.com') in validuids) |
161 | - self.assertTrue((test_fpr, 'sample.revoked@canonical.com') |
162 | - not in validuids) |
163 | - |
164 | - # foo.bar@canonical.com's non-revoked signed UIDs are valid |
165 | - self.assertTrue((foobar_fpr, 'foo.bar@canonical.com') in validuids) |
166 | - self.assertTrue((foobar_fpr, |
167 | - 'revoked@canonical.com') not in validuids) |
168 | - self.assertTrue((foobar_fpr, 'untrusted@canonical.com') |
169 | - not in validuids) |
170 | - |
171 | - def testFindEmailClusters(self): |
172 | - """Test findEmailClusters""" |
173 | - self._addTrustedKeys() |
174 | - self._addUntrustedKeys() |
175 | - |
176 | - clusters = list(findEmailClusters()) |
177 | - |
178 | - # test@canonical.com is ultimately trusted, so its non-revoked keys |
179 | - # form a cluster |
180 | - self.assertTrue(set(['test@canonical.com', |
181 | - 'sample.person@canonical.com']) in clusters) |
182 | - |
183 | - # foobar has only one signed, non-revoked key |
184 | - self.assertTrue(set(['foo.bar@canonical.com']) in clusters) |
185 | - |
186 | - |
187 | -class TestMergeClusters(unittest.TestCase): |
188 | - """Tests of the mergeClusters() routine.""" |
189 | - layer = LaunchpadZopelessLayer |
190 | - |
191 | - def _getEmails(self, person): |
192 | - emailset = getUtility(IEmailAddressSet) |
193 | - return set(address.email for address in emailset.getByPerson(person)) |
194 | - |
195 | - def testNullMerge(self): |
196 | - """Test that a merge with an empty sequence of clusters works""" |
197 | - mergeClusters([]) |
198 | - |
199 | - def testMergeOneAccountNoNewEmails(self): |
200 | - """Test that merging a single email address does not affect an |
201 | - account. |
202 | - """ |
203 | - person = getUtility(IPersonSet).getByEmail('test@canonical.com') |
204 | - emails = self._getEmails(person) |
205 | - self.assertTrue('test@canonical.com' in emails) |
206 | - self.assertEqual(person.merged, None) |
207 | - |
208 | - mergeClusters([set(['test@canonical.com'])]) |
209 | - self.assertEqual(person.merged, None) |
210 | - self.assertEqual(self._getEmails(person), emails) |
211 | - |
212 | - def testMergeOneAccountAddEmails(self): |
213 | - """Test that merging a cluster containing new email addresses adds |
214 | - those emails. |
215 | - """ |
216 | - personset = getUtility(IPersonSet) |
217 | - emailset = getUtility(IEmailAddressSet) |
218 | - |
219 | - person = personset.getByEmail('test@canonical.com') |
220 | - self.assertEqual(person.merged, None) |
221 | - # make sure newemail doesn't exist |
222 | - self.assertEqual(personset.getByEmail('newemail@canonical.com'), None) |
223 | - |
224 | - mergeClusters([set(['test@canonical.com', 'newemail@canonical.com'])]) |
225 | - self.assertEqual(person.merged, None) |
226 | - emails = self._getEmails(person) |
227 | - |
228 | - # both email addresses associated with account ... |
229 | - self.assertTrue('test@canonical.com' in emails) |
230 | - self.assertTrue('newemail@canonical.com' in emails) |
231 | - |
232 | - address = emailset.getByEmail('newemail@canonical.com') |
233 | - self.assertEqual(address.email, 'newemail@canonical.com') |
234 | - self.assertEqual(address.personID, person.id) |
235 | - self.assertEqual(address.status, EmailAddressStatus.NEW) |
236 | - |
237 | - def testMergeUnvalidatedAccountWithValidated(self): |
238 | - """Test merging an unvalidated account with a validated account.""" |
239 | - personset = getUtility(IPersonSet) |
240 | - |
241 | - validated_person = personset.getByEmail('test@canonical.com') |
242 | - unvalidated_person = personset.getByEmail( |
243 | - 'matsubara@async.com.br') |
244 | - |
245 | - allemails = self._getEmails(validated_person) |
246 | - allemails.update(self._getEmails(unvalidated_person)) |
247 | - |
248 | - self.assertNotEqual(validated_person, unvalidated_person) |
249 | - |
250 | - self.assertNotEqual(validated_person.preferredemail, None) |
251 | - self.assertEqual(unvalidated_person.preferredemail, None) |
252 | - |
253 | - self.assertEqual(validated_person.merged, None) |
254 | - self.assertEqual(unvalidated_person.merged, None) |
255 | - |
256 | - mergeClusters([set(['test@canonical.com', |
257 | - 'matsubara@async.com.br'])]) |
258 | - |
259 | - # unvalidated person has been merged into the validated person |
260 | - self.assertEqual(validated_person.merged, None) |
261 | - self.assertEqual(unvalidated_person.merged, validated_person) |
262 | - |
263 | - # all email addresses are now associated with the valid person |
264 | - self.assertEqual(self._getEmails(validated_person), allemails) |
265 | - self.assertEqual(self._getEmails(unvalidated_person), set()) |
266 | - |
267 | - def testMergeTwoValidatedAccounts(self): |
268 | - """Test merging of two validated accounts. This should do |
269 | - nothing, since both accounts are in use. |
270 | - """ |
271 | - personset = getUtility(IPersonSet) |
272 | - |
273 | - person1 = personset.getByEmail('test@canonical.com') |
274 | - person2 = personset.getByEmail('foo.bar@canonical.com') |
275 | - self.assertNotEqual(person1, person2) |
276 | - |
277 | - self.assertNotEqual(person1.preferredemail, None) |
278 | - self.assertNotEqual(person2.preferredemail, None) |
279 | - |
280 | - self.assertEqual(person1.merged, None) |
281 | - self.assertEqual(person2.merged, None) |
282 | - |
283 | - logger, collector = setupLogger() |
284 | - mergeClusters([set(['test@canonical.com', 'foo.bar@canonical.com'])], |
285 | - logger=logger) |
286 | - |
287 | - self.assertEqual(person1.merged, None) |
288 | - self.assertEqual(person2.merged, None) |
289 | - |
290 | - messages = collector.records |
291 | - self.assertNotEqual(messages, []) |
292 | - self.assertTrue(messages[0].startswith('WARNING:Multiple validated ' |
293 | - 'user accounts')) |
294 | - |
295 | - def testMergeTwoUnvalidatedAccounts(self): |
296 | - """Test merging of two unvalidated accounts. This will pick |
297 | - one account and merge the others into it (since none of the |
298 | - accounts have been used, there is no need to favour one over |
299 | - the other). |
300 | - """ |
301 | - personset = getUtility(IPersonSet) |
302 | - |
303 | - person1 = personset.getByEmail('matsubara@async.com.br') |
304 | - person2 = personset.getByEmail('martin.pitt@canonical.com') |
305 | - |
306 | - allemails = self._getEmails(person1) |
307 | - allemails.update(self._getEmails(person2)) |
308 | - |
309 | - self.assertEqual(person1.preferredemail, None) |
310 | - self.assertEqual(person2.preferredemail, None) |
311 | - |
312 | - self.assertEqual(person1.merged, None) |
313 | - self.assertEqual(person2.merged, None) |
314 | - |
315 | - mergeClusters([set(['matsubara@async.com.br', |
316 | - 'martin.pitt@canonical.com'])]) |
317 | - |
318 | - # since we don't know which account will be merged, swap |
319 | - # person1 and person2 if person1 was merged into person2. |
320 | - if person1.merged is not None: |
321 | - person1, person2 = person2, person1 |
322 | - |
323 | - # one account is merged into the other |
324 | - self.assertEqual(person1.merged, None) |
325 | - self.assertEqual(person2.merged, person1) |
326 | - |
327 | - self.assertEqual(self._getEmails(person1), allemails) |
328 | - self.assertEqual(self._getEmails(person2), set()) |
329 | - |
330 | - def testMergeUnknownEmail(self): |
331 | - """Merging a cluster of unknown emails creates an account.""" |
332 | - personset = getUtility(IPersonSet) |
333 | - |
334 | - self.assertEqual(personset.getByEmail('newemail@canonical.com'), None) |
335 | - |
336 | - mergeClusters([set(['newemail@canonical.com'])]) |
337 | - |
338 | - person = personset.getByEmail('newemail@canonical.com') |
339 | - self.assertNotEqual(person, None) |
340 | - self.assertEqual(person.preferredemail, None) |
341 | - self.assertTrue('newemail@canonical.com' in self._getEmails(person)) |
342 | |
343 | === modified file 'lib/canonical/launchpad/utilities/ftests/test_gpghandler.py' |
344 | --- lib/canonical/launchpad/utilities/ftests/test_gpghandler.py 2011-08-16 20:35:11 +0000 |
345 | +++ lib/canonical/launchpad/utilities/ftests/test_gpghandler.py 2011-08-22 01:12:25 +0000 |
346 | @@ -149,54 +149,6 @@ |
347 | """Do we have the expected test keyring files""" |
348 | self.assertEqual(len(list(keys_for_tests.test_keyrings())), 1) |
349 | |
350 | - def testImportKeyRing(self): |
351 | - """Import a sample keyring and check its contents are available.""" |
352 | - self.testEmptyGetKeys() |
353 | - importedkeys = set() |
354 | - for ring in keys_for_tests.test_keyrings(): |
355 | - keys = self.gpg_handler.importKeyringFile(ring) |
356 | - importedkeys.update(key.fingerprint for key in keys) |
357 | - |
358 | - # check that expected keys are in importedkeys set |
359 | - self.assertTrue("340CA3BB270E2716C9EE0B768E7EB7086C64A8C5" |
360 | - in importedkeys) |
361 | - self.assertTrue("A419AE861E88BC9E04B9C26FBA2B9389DFD20543" |
362 | - in importedkeys) |
363 | - |
364 | - # check that importedkeys are in key ring |
365 | - keyring = set(key.fingerprint |
366 | - for key in self.gpg_handler.localKeys()) |
367 | - self.assertNotEqual(len(keyring), 0) |
368 | - self.assertTrue(importedkeys.issubset(keyring)) |
369 | - |
370 | - def testSetOwnerTrust(self): |
371 | - """Import a key and set the ownertrust.""" |
372 | - self.testEmptyGetKeys() |
373 | - for email in keys_for_tests.iter_test_key_emails(): |
374 | - pubkey = keys_for_tests.test_pubkey_from_email(email) |
375 | - self.gpg_handler.importPublicKey(pubkey) |
376 | - |
377 | - iterator = self.gpg_handler.localKeys() |
378 | - key = iterator.next() |
379 | - self.assertEqual(key.owner_trust, gpgme.VALIDITY_UNKNOWN) |
380 | - key.setOwnerTrust(gpgme.VALIDITY_FULL) |
381 | - self.assertEqual(key.owner_trust, gpgme.VALIDITY_FULL) |
382 | - other_iterator = self.gpg_handler.localKeys() |
383 | - other_key_instance = other_iterator.next() |
384 | - self.assertEqual(key.owner_trust, other_key_instance.owner_trust) |
385 | - |
386 | - def testCheckTrustDb(self): |
387 | - """Test IGPGHandler.checkTrustDb()""" |
388 | - self.testEmptyGetKeys() |
389 | - |
390 | - # check trust DB with no keys succeeds |
391 | - self.assertEqual(self.gpg_handler.checkTrustDb(), 0) |
392 | - |
393 | - # add some keys and check trust DB again |
394 | - for ring in keys_for_tests.test_keyrings(): |
395 | - self.gpg_handler.importKeyringFile(ring) |
396 | - self.assertEqual(self.gpg_handler.checkTrustDb(), 0) |
397 | - |
398 | def testHomeDirectoryJob(self): |
399 | """Does the job to touch the home work.""" |
400 | gpghandler = getUtility(IGPGHandler) |
401 | @@ -224,9 +176,7 @@ |
402 | def test_retrieveKey_raises_GPGKeyDoesNotExistOnServer(self): |
403 | # GPGHandler.retrieveKey() raises GPGKeyDoesNotExistOnServer |
404 | # when called for a key that does not exist on the key server. |
405 | - tac = KeyServerTac() |
406 | - tac.setUp() |
407 | - self.addCleanup(tac.tearDown) |
408 | + self.useFixture(KeyServerTac()) |
409 | gpghandler = getUtility(IGPGHandler) |
410 | self.assertRaises( |
411 | GPGKeyDoesNotExistOnServer, gpghandler.retrieveKey, |
412 | @@ -236,7 +186,7 @@ |
413 | self): |
414 | # If the keyserver responds too slowly, GPGHandler.retrieveKey() |
415 | # raises GPGKeyTemporarilyNotFoundError. |
416 | - tac = self.useFixture(KeyServerTac()) |
417 | + self.useFixture(KeyServerTac()) |
418 | old_timeout_function = get_default_timeout_function() |
419 | set_default_timeout_function(lambda: 0.01) |
420 | try: |
421 | |
422 | === modified file 'lib/canonical/launchpad/utilities/gpghandler.py' |
423 | --- lib/canonical/launchpad/utilities/gpghandler.py 2011-06-01 13:32:02 +0000 |
424 | +++ lib/canonical/launchpad/utilities/gpghandler.py 2011-08-22 01:12:25 +0000 |
425 | @@ -24,7 +24,6 @@ |
426 | import urllib2 |
427 | |
428 | import gpgme |
429 | -from gpgme import editutil as gpgme_editutil |
430 | from zope.interface import implements |
431 | |
432 | from canonical.config import config |
433 | @@ -344,18 +343,6 @@ |
434 | |
435 | return key |
436 | |
437 | - def importKeyringFile(self, filepath): |
438 | - """See IGPGHandler.importKeyringFile.""" |
439 | - ctx = gpgme.Context() |
440 | - data = open(filepath, 'r') |
441 | - result = ctx.import_(data) |
442 | - # if not considered -> format wasn't recognized |
443 | - # no key was imported |
444 | - if result.considered == 0: |
445 | - raise ValueError('Empty or invalid keyring') |
446 | - return [PymeKey(fingerprint) |
447 | - for (fingerprint, result, status) in result.imports] |
448 | - |
449 | def encryptContent(self, content, fingerprint): |
450 | """See IGPGHandler.""" |
451 | if isinstance(content, unicode): |
452 | @@ -541,16 +528,6 @@ |
453 | url = self.getURLForKeyInServer(fingerprint, action) |
454 | return urlfetch(url) |
455 | |
456 | - def checkTrustDb(self): |
457 | - """See IGPGHandler""" |
458 | - p = subprocess.Popen(['gpg', '--check-trustdb', '--batch', '--yes'], |
459 | - close_fds=True, |
460 | - stdin=subprocess.PIPE, |
461 | - stdout=subprocess.PIPE, |
462 | - stderr=subprocess.STDOUT) |
463 | - p.communicate() |
464 | - return p.returncode |
465 | - |
466 | |
467 | class PymeSignature(object): |
468 | """See IPymeSignature.""" |
469 | @@ -617,19 +594,6 @@ |
470 | self.emails = [uid.email for uid in self.uids |
471 | if valid_email(uid.email) and not uid.revoked] |
472 | |
473 | - def setOwnerTrust(self, value): |
474 | - """Set the ownertrust on the actual gpg key""" |
475 | - if value not in (gpgme.VALIDITY_UNDEFINED, gpgme.VALIDITY_NEVER, |
476 | - gpgme.VALIDITY_MARGINAL, gpgme.VALIDITY_FULL, |
477 | - gpgme.VALIDITY_ULTIMATE): |
478 | - raise ValueError("invalid owner trust level") |
479 | - # edit the owner trust value on the key |
480 | - ctx = gpgme.Context() |
481 | - key = ctx.get_key(self.fingerprint.encode('ascii'), False) |
482 | - gpgme_editutil.edit_trust(ctx, key, value) |
483 | - # set the cached copy of owner_trust |
484 | - self.owner_trust = value |
485 | - |
486 | @property |
487 | def displayname(self): |
488 | return '%s%s/%s' % (self.keysize, self.algorithm, self.keyid) |
489 | |
490 | === removed file 'lib/lp/registry/scripts/keyringtrustanalyser.py' |
491 | --- lib/lp/registry/scripts/keyringtrustanalyser.py 2011-02-23 20:26:53 +0000 |
492 | +++ lib/lp/registry/scripts/keyringtrustanalyser.py 1970-01-01 00:00:00 +0000 |
493 | @@ -1,183 +0,0 @@ |
494 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
495 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
496 | - |
497 | -import gpgme |
498 | -from zope.component import getUtility |
499 | - |
500 | -from canonical.database.sqlbase import flush_database_updates |
501 | -from canonical.launchpad.interfaces.emailaddress import IEmailAddressSet |
502 | -from canonical.launchpad.interfaces.gpghandler import IGPGHandler |
503 | -from lp.app.validators.email import valid_email |
504 | -from lp.registry.interfaces.person import ( |
505 | - IPersonSet, |
506 | - PersonCreationRationale, |
507 | - ) |
508 | - |
509 | - |
510 | -__metaclass__ = type |
511 | - |
512 | -__all__ = [ |
513 | - 'addTrustedKeyring', |
514 | - 'addOtherKeyring', |
515 | - 'getValidUids', |
516 | - 'findEmailClusters', |
517 | - 'mergeClusters', |
518 | - ] |
519 | - |
520 | -def addTrustedKeyring(filename, ownertrust=gpgme.VALIDITY_MARGINAL): |
521 | - """Add a keyring of keys owned by people trusted to make good signatues. |
522 | - """ |
523 | - gpg = getUtility(IGPGHandler) |
524 | - keys = gpg.importKeyringFile(filename) |
525 | - for key in keys: |
526 | - key.setOwnerTrust(ownertrust) |
527 | - |
528 | -def addOtherKeyring(filename): |
529 | - """Add a keyring of possibly suspect keys""" |
530 | - gpg = getUtility(IGPGHandler) |
531 | - gpg.importKeyringFile(filename) |
532 | - |
533 | -def getValidUids(minvalid=gpgme.VALIDITY_MARGINAL): |
534 | - """Returns an iterator yielding (fingerprint, email) pairs. |
535 | - |
536 | - Only UIDs assigned a validity of at least 'minvalid' are returned. |
537 | - """ |
538 | - gpg = getUtility(IGPGHandler) |
539 | - gpg.checkTrustDb() |
540 | - for key in gpg.localKeys(): |
541 | - for uid in key.uids: |
542 | - if (not uid.revoked and valid_email(uid.email) and |
543 | - uid.validity >= minvalid): |
544 | - yield key.fingerprint, uid.email |
545 | - |
546 | -def findEmailClusters(minvalid=gpgme.VALIDITY_MARGINAL): |
547 | - """Returns an iterator yielding sets of related email addresses. |
548 | - |
549 | - Two email addresses are considered to be related if they appear as |
550 | - valid user IDs on a PGP key in the keyring. |
551 | - """ |
552 | - emails = {} # fingerprint -> set(emails) |
553 | - fingerprints = {} # email -> set(fingerprints) |
554 | - |
555 | - # get the valid UIDs |
556 | - for fpr, email in getValidUids(minvalid): |
557 | - fingerprints.setdefault(email, set()).add(fpr) |
558 | - emails.setdefault(fpr, set()).add(email) |
559 | - |
560 | - # find clusters of keys based on the presence of shared valid UIDs |
561 | - clusters = {} # fingerprint -> set(fingerprints) |
562 | - for fprs in fingerprints.itervalues(): |
563 | - cluster = fprs.copy() |
564 | - for fpr in fprs: |
565 | - x = clusters.get(fpr) |
566 | - if x is not None: |
567 | - cluster.update(x) |
568 | - for fpr in cluster: |
569 | - clusters[fpr] = cluster |
570 | - |
571 | - # return email addresses belonging to each key cluster |
572 | - for cluster in clusters.itervalues(): |
573 | - email_cluster = set() |
574 | - for fpr in cluster: |
575 | - email_cluster.update(emails[fpr]) |
576 | - yield email_cluster |
577 | - |
578 | -def _mergeOrAddEmails(personset, emailset, cluster, logger): |
579 | - """Helper function for mergeClusters() |
580 | - |
581 | - The strategy for merging clusters is as follows: |
582 | - 1. Find all Person objects attached to the given email addresses. |
583 | - 2. If there is more than one Person object associated with the cluster, |
584 | - merge them into one (merge into Person with preferred email). |
585 | - 3. If there are no Person objects associated with the cluster, create |
586 | - a new person. |
587 | - 4. For each email address not associated with the person or awaiting |
588 | - validation, add it to the person in state NEW (unvalidated). |
589 | - |
590 | - This algorithm does not handle the case where two accounts have a |
591 | - preferred email. This situation would indicate that users have |
592 | - logged in as both identities, and we don't want to kill accounts |
593 | - for no reason. |
594 | - """ |
595 | - # get a list of Person objects associated with this address cluster |
596 | - people = set() |
597 | - for email in cluster: |
598 | - person = personset.getByEmail(email) |
599 | - if person: |
600 | - people.add(person) |
601 | - |
602 | - if len(people) > 1: |
603 | - # more than one Person object => account merge. |
604 | - |
605 | - # Check if any of the accounts have been used. |
606 | - # If one account has been used, we want to merge the others |
607 | - # into that one. |
608 | - # If more than one account has been used, bail. |
609 | - |
610 | - validpeople = set(person for person in people |
611 | - if person.preferredemail is not None) |
612 | - if len(validpeople) > 1: |
613 | - if logger: |
614 | - logger.warning('Multiple validated user accounts found for cluster %r: %s', |
615 | - cluster, |
616 | - ', '.join(['%s (%d)' % (person.name, person.id) |
617 | - for person in validpeople])) |
618 | - return None |
619 | - elif len(validpeople) == 1: |
620 | - person = validpeople.pop() |
621 | - people.remove(person) |
622 | - else: |
623 | - # no validated accounts -- pick one at random |
624 | - person = people.pop() |
625 | - |
626 | - # assign email addresses |
627 | - from zope.security.proxy import removeSecurityProxy |
628 | - for otherperson in people: |
629 | - for email in emailset.getByPerson(otherperson): |
630 | - # EmailAddress.person is a readonly field, so we need to |
631 | - # remove the security proxy here. |
632 | - removeSecurityProxy(email).personID = person.id |
633 | - |
634 | - # merge people |
635 | - for otherperson in people: |
636 | - if logger: |
637 | - logger.info('Merging %s (%d) into %s (%d)', |
638 | - otherperson.name, otherperson.id, |
639 | - person.name, person.id) |
640 | - personset.merge(otherperson, person) |
641 | - |
642 | - elif len(people) == 1: |
643 | - # one person: use that |
644 | - person = people.pop() |
645 | - else: |
646 | - # no person? create it. |
647 | - # We should have the display name from a key here ... |
648 | - person, email = personset.createPersonAndEmail( |
649 | - cluster.pop(), PersonCreationRationale.KEYRINGTRUSTANALYZER) |
650 | - |
651 | - # We now have one person. Now add the missing addresses: |
652 | - existing = set(email.email for email in emailset.getByPerson(person)) |
653 | - existing.update(person.unvalidatedemails) |
654 | - for newemail in cluster.difference(existing): |
655 | - if logger: |
656 | - logger.info('Adding email %s to %s (%d)', |
657 | - newemail, person.name, person.id) |
658 | - emailset.new(email=newemail, person=person, account=person.account) |
659 | - |
660 | - flush_database_updates() |
661 | - |
662 | - return person |
663 | - |
664 | -def mergeClusters(clusters, ztm=None, logger=None): |
665 | - """Merge accounts for clusters of addresses. |
666 | - |
667 | - The first argument is an iterator returning sets of email addresses. |
668 | - """ |
669 | - personset = getUtility(IPersonSet) |
670 | - emailset = getUtility(IEmailAddressSet) |
671 | - for cluster in clusters: |
672 | - if not cluster: continue |
673 | - |
674 | - if ztm: ztm.begin() |
675 | - _mergeOrAddEmails(personset, emailset, cluster, logger) |
676 | - if ztm: ztm.commit() |
677 | |
678 | === removed file 'scripts/find-email-clusters.py' |
679 | --- scripts/find-email-clusters.py 2010-04-27 19:48:39 +0000 |
680 | +++ scripts/find-email-clusters.py 1970-01-01 00:00:00 +0000 |
681 | @@ -1,101 +0,0 @@ |
682 | -#!/usr/bin/python -S |
683 | -# |
684 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
685 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
686 | - |
687 | -# pylint: disable-msg=W0403 |
688 | -import _pythonpath |
689 | - |
690 | -import sys |
691 | -import logging |
692 | -import optparse |
693 | - |
694 | -import gpgme |
695 | - |
696 | -from canonical.launchpad.scripts import ( |
697 | - execute_zcml_for_scripts, logger_options, logger as logger_from_options) |
698 | -from lp.registry.scripts.keyringtrustanalyser import ( |
699 | - addOtherKeyring, addTrustedKeyring, findEmailClusters) |
700 | - |
701 | - |
702 | -validity_map = { |
703 | - 'UNDEFINED': gpgme.VALIDITY_UNDEFINED, |
704 | - 'NEVER': gpgme.VALIDITY_NEVER, |
705 | - 'MARGINAL': gpgme.VALIDITY_MARGINAL, |
706 | - 'FULL': gpgme.VALIDITY_FULL, |
707 | - 'ULTIMATE': gpgme.VALIDITY_ULTIMATE, |
708 | - } |
709 | - |
710 | - |
711 | -def main(argv): |
712 | - parser = optparse.OptionParser( |
713 | - usage="usage: %prog [options] keyrings ...", |
714 | - description="This script inferrs clusters of " |
715 | - "email addresses belonging to a single user " |
716 | - "from the user IDs attached to PGP keys.") |
717 | - parser.add_option('-o', '--output', metavar='FILE', action='store', |
718 | - help='Output clusters to given file', |
719 | - type='string', dest='output', default=None) |
720 | - parser.add_option('--trust', metavar='KEYRING', action='append', |
721 | - help='Trust the owners of keys on this keyring', |
722 | - type='string', dest='trust', default=[]) |
723 | - parser.add_option('--owner-trust', metavar='TRUST', action='store', |
724 | - help='What level of trust to assign to trusted keys', |
725 | - type='string', dest='owner_trust', default='ULTIMATE') |
726 | - parser.add_option('--min-valid', metavar='TRUST', action='store', |
727 | - help='Minimum trust necessary for a user ID to ' |
728 | - 'be considered valid', |
729 | - type='string', dest='minvalid', default='MARGINAL') |
730 | - |
731 | - logger_options(parser, logging.WARNING) |
732 | - |
733 | - options, args = parser.parse_args(argv[1:]) |
734 | - |
735 | - # map validity options |
736 | - if options.owner_trust.upper() not in validity_map: |
737 | - sys.stderr.write('%s: unknown owner trust value %s' |
738 | - % (argv[0], options.owner_trust)) |
739 | - return 1 |
740 | - options.owner_trust = validity_map[options.owner_trust.upper()] |
741 | - |
742 | - if options.minvalid.upper() not in validity_map: |
743 | - sys.stderr.write('%s: unknown min valid value %s' |
744 | - % (argv[0], options.minvalid)) |
745 | - return 1 |
746 | - options.minvalid = validity_map[options.minvalid.upper()] |
747 | - |
748 | - # get logger |
749 | - logger = logger_from_options(options) |
750 | - |
751 | - if options.output is not None: |
752 | - logger.debug('openning %s', options.output) |
753 | - fp = open(options.output, 'w') |
754 | - else: |
755 | - fp = sys.stdout |
756 | - |
757 | - logger.info('Setting up utilities') |
758 | - execute_zcml_for_scripts() |
759 | - |
760 | - logger.info('Loading trusted keyrings') |
761 | - for keyring in options.trust: |
762 | - logger.info('Loading %s', keyring) |
763 | - addTrustedKeyring(keyring, options.owner_trust) |
764 | - |
765 | - logger.info('Loading other keyrings') |
766 | - for keyring in args: |
767 | - logger.info('Loading %s', keyring) |
768 | - addOtherKeyring(keyring) |
769 | - |
770 | - logger.info('Computing address clusters') |
771 | - for cluster in findEmailClusters(options.minvalid): |
772 | - for email in cluster: |
773 | - fp.write('%s\n' % email) |
774 | - fp.write('\n') |
775 | - |
776 | - logger.info('Done') |
777 | - |
778 | - return 0 |
779 | - |
780 | - |
781 | -if __name__ == '__main__': |
782 | - sys.exit(main(sys.argv)) |
783 | |
784 | === removed file 'scripts/merge-email-clusters.py' |
785 | --- scripts/merge-email-clusters.py 2010-04-27 19:48:39 +0000 |
786 | +++ scripts/merge-email-clusters.py 1970-01-01 00:00:00 +0000 |
787 | @@ -1,71 +0,0 @@ |
788 | -#!/usr/bin/python -S |
789 | -# |
790 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
791 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
792 | - |
793 | -# pylint: disable-msg=W0403 |
794 | -import _pythonpath |
795 | - |
796 | -import sys |
797 | -import logging |
798 | -import optparse |
799 | - |
800 | -from canonical.lp import initZopeless |
801 | -from canonical.launchpad.scripts import ( |
802 | - execute_zcml_for_scripts, logger_options, logger as logger_from_options) |
803 | -from lp.registry.scripts.keyringtrustanalyser import mergeClusters |
804 | - |
805 | - |
806 | -def readClusters(fp): |
807 | - """Read clusters of email addresses from the file (separated by blank |
808 | - lines), and yield them as sets.""" |
809 | - cluster = set() |
810 | - for line in fp: |
811 | - line = line.strip() |
812 | - if line: |
813 | - cluster.add(line) |
814 | - elif cluster: |
815 | - yield cluster |
816 | - cluster = set() |
817 | - if cluster: |
818 | - yield cluster |
819 | - |
820 | - |
821 | -def main(argv): |
822 | - parser = optparse.OptionParser( |
823 | - description="This script reads a list of email address clusters. " |
824 | - "and updates the Launchpad database to match by adding email " |
825 | - "addresses to existing accounts, merging accounts and " |
826 | - "creating new accounts") |
827 | - parser.add_option('-i', '--input', metavar='FILE', action='store', |
828 | - help='Read clusters from the given file', |
829 | - type='string', dest='input', default=None) |
830 | - |
831 | - logger_options(parser, logging.WARNING) |
832 | - |
833 | - options, args = parser.parse_args(argv[1:]) |
834 | - |
835 | - # get logger |
836 | - logger = logger_from_options(options) |
837 | - |
838 | - if options.input is not None: |
839 | - logger.debug('openning %s', options.input) |
840 | - fp = open(options.input, 'r') |
841 | - else: |
842 | - fp = sys.stdin |
843 | - |
844 | - logger.info('Setting up utilities') |
845 | - execute_zcml_for_scripts() |
846 | - |
847 | - logger.info('Connecting to database') |
848 | - ztm = initZopeless() |
849 | - |
850 | - mergeClusters(readClusters(fp), ztm, logger) |
851 | - |
852 | - logger.info('Done') |
853 | - |
854 | - return 0 |
855 | - |
856 | - |
857 | -if __name__ == '__main__': |
858 | - sys.exit(main(sys.argv)) |
./lib/canonical /launchpad/ utilities/ gpghandler. py /launchpad/ utilities/ ftests/ test_gpghandler .py
27: 'gpgme_editutil' imported but unused
./lib/canonical
191: local variable 'tac' is assigned to but never used
13: 'gpgme' imported but unused
The first one is yours, the other two might not be.