Code review comment for lp:~wgrant/launchpad/make-zeca-useful

Revision history for this message
William Grant (wgrant) wrote :

On Wed, 2009-08-19 at 23:38 +0000, Celso Providelo wrote:
> Review: Needs Fixing code
> Willian,
>
> This change is definitely going in the right direction, thanks for proposing it!
>
> On the current diff I can only point the fact that, when found by glob, the key file content is not escaped, which will result in a broken HTML page.

Fixed. Oops.

> As we discussed on IRC, we could take the opportunity to extract the code used to locate key files and make this part of the application much nicer than it is, maybe plugging new key lookup mechanisms later.
>
> I'd suggest locate_key(root, term), 'root' is static, but it might be easier to pass it in. Doing that we can also cover most of its aspects with unittests.

I've extracted it into c.z.z.locate_key, with tests in
c.z.z.ftests.test_locate_key.

I considered removing some of the tests from c.z.z.ftests.harness, but
they're short and relevant enough that it seems good to leave them
there.

> Looking forward to see the incremental patch.

Thanks for the review! The diff is attached.

--
William Grant

1=== added file 'lib/canonical/zeca/ftests/test_locate_key.py'
2--- lib/canonical/zeca/ftests/test_locate_key.py 1970-01-01 00:00:00 +0000
3+++ lib/canonical/zeca/ftests/test_locate_key.py 2009-08-20 01:01:54 +0000
4@@ -0,0 +1,43 @@
5+# Copyright 2009 Canonical Ltd. This software is licensed under the
6+# GNU Affero General Public License version 3 (see the file LICENSE).
7+
8+import unittest
9+import os.path
10+
11+from canonical.zeca.zeca import locate_key
12+
13+
14+class LocateKeyTestCase(unittest.TestCase):
15+ root = os.path.join(os.path.dirname(__file__), 'keys')
16+
17+ def assertKeyFile(self, suffix, filename):
18+ """Verify that a suffix maps to the given filename."""
19+
20+ if filename is not None:
21+ filename = os.path.join(self.root, filename)
22+ self.assertEqual(locate_key(self.root, suffix), filename)
23+
24+ def test_exact_fingerprint_match(self):
25+ self.assertKeyFile(
26+ '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get',
27+ '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
28+
29+ def test_keyid_glob_match(self):
30+ self.assertKeyFile(
31+ '0xDFD20543.get',
32+ '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
33+
34+ def test_keyid_without_prefix_glob_match(self):
35+ self.assertKeyFile(
36+ 'DFD20543.get',
37+ '0xA419AE861E88BC9E04B9C26FBA2B9389DFD20543.get')
38+
39+ def test_keyid_no_match(self):
40+ self.assertKeyFile('0xDEADBEEF.get', None)
41+
42+
43+def test_suite():
44+ suite = unittest.TestSuite()
45+ suite.addTest(unittest.makeSuite(LocateKeyTestCase))
46+ return suite
47+
48
49=== modified file 'lib/canonical/zeca/zeca.py'
50--- lib/canonical/zeca/zeca.py 2009-08-15 03:47:48 +0000
51+++ lib/canonical/zeca/zeca.py 2009-08-20 01:07:44 +0000
52@@ -9,12 +9,13 @@
53
54 - 'index' : returns key index information
55 - 'get': returns an ASCII armored public key
56-
57-It does not depend on GPG; it simply serves the information stored in
58-files at a given HOME (default to /home/keys/) with the following name
59-format:
60-
61-0x<keyid>.<operation>
62+ - 'add': adds a key to the collection (does not update the index)
63+
64+It only depends on GPG for key submission; for retrieval and searching
65+it just looks for files in the root (eg. /var/tmp/zeca). The files
66+are named like this:
67+
68+0x<keyid|fingerprint>.<operation>
69
70 Example:
71
72@@ -51,6 +52,33 @@
73 GREETING = 'Copyright 2004-2008 Canonical Ltd.\n'
74
75
76+def locate_key(root, suffix):
77+ """Find a key file in the root with the given suffix.
78+
79+ This does some globbing to possibly find a fingerprint-named key
80+ file when given a key ID.
81+
82+ :param root: The root directory in which to look.
83+ :param suffix: The key ID or fingerprint, of the form
84+ 0x<FINGERPRINT|KEYID>.<METHOD>
85+ :returns: An absolute path to the key file.
86+ """
87+ path = os.path.join(root, suffix)
88+
89+ if not os.path.exists(path):
90+ # GPG might request a key ID from us, but we name the keys by
91+ # fingerprint. Let's glob.
92+ if suffix.startswith('0x'):
93+ suffix = suffix[2:]
94+ keys = glob.glob(os.path.join(root, '*'+suffix))
95+ if len(keys) == 1:
96+ path = keys[0]
97+ else:
98+ return None
99+
100+ return path
101+
102+
103 class Zeca(Resource):
104 def getChild(self, name, request):
105 if name == '':
106@@ -96,22 +124,11 @@
107
108 filename = '%s.%s' % (keyid, action)
109
110- try:
111- path = os.path.join(self.root, filename)
112- fp = open(path)
113- except IOError:
114- # GPG might request a key ID from us, but we name the keys by
115- # fingerprint. Let's glob.
116- if filename.startswith('0x'):
117- filename = filename[2:]
118- keys = glob.glob(os.path.join(self.root, '*'+filename))
119- if len(keys) == 1:
120- content = open(keys[0]).read()
121- else:
122- content = 'Key Not Found'
123+ path = locate_key(self.root, filename)
124+ if path is not None:
125+ content = cgi.escape(open(path).read())
126 else:
127- content = cgi.escape(fp.read())
128- fp.close()
129+ content = 'Key Not Found'
130
131 page += '<pre>\n%s\n</pre>\n</html>' % content
132

« Back to merge proposal