Moved help_box to zeroinstall.gtkui.
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / 0launch-gui / trust_box.py
blob1f38e6633da5cfb8ca072f83fdedd1b16dc36d09
1 # Copyright (C) 2008, Thomas Leonard
2 # -*- coding: utf-8 -*-
3 # See the README file for details, or visit http://0install.net.
5 import gtk
6 from zeroinstall.injector.model import SafeException
7 from zeroinstall.injector import gpg, trust
8 from zeroinstall.injector.iface_cache import iface_cache
9 from zeroinstall.support import tasks
10 from zeroinstall.gtkui import help_box
12 import gui
13 import dialog
15 def pretty_fp(fp):
16 s = fp[0:4]
17 for x in range(4, len(fp), 4):
18 s += ' ' + fp[x:x + 4]
19 return s
21 class TrustBox(dialog.Dialog):
22 interface = None
23 sigs = None
24 iface_xml = None
25 valid_sigs = None
26 parent = None
27 closed = None
29 def __init__(self, interface, sigs, iface_xml, parent):
30 dialog.Dialog.__init__(self)
31 self.set_transient_for(parent)
33 self.closed = tasks.Blocker("confirming keys with user")
35 domain = trust.domain_from_url(interface.uri)
36 assert domain
38 def destroy(box):
39 global _queue
40 assert _queue[0] is self
41 del _queue[0]
43 self.closed.trigger()
45 # Remove any queued boxes that are no longer required
46 def still_untrusted(box):
47 for sig in box.valid_sigs:
48 is_trusted = trust.trust_db.is_trusted(sig.fingerprint, domain)
49 if is_trusted:
50 return False
51 return True
52 if _queue:
53 next = _queue[0]
54 if still_untrusted(next):
55 next.show()
56 else:
57 next.trust_keys([], domain)
58 next.destroy() # Will trigger this again...
59 self.connect('destroy', destroy)
61 def left(text):
62 label = gtk.Label(text)
63 label.set_alignment(0, 0.5)
64 label.set_selectable(True)
65 return label
67 self.interface = interface
68 self.sigs = sigs
69 self.iface_xml = iface_xml
71 self.set_title('Confirm trust')
73 vbox = gtk.VBox(False, 4)
74 vbox.set_border_width(4)
75 self.vbox.pack_start(vbox, True, True, 0)
77 self.valid_sigs = [s for s in sigs if isinstance(s, gpg.ValidSig)]
78 if not self.valid_sigs:
79 raise SafeException('No valid signatures found. Signatures:' +
80 ''.join(['\n- ' + str(s) for s in sigs]))
82 notebook = gtk.Notebook()
84 if len(self.valid_sigs) == 1:
85 notebook.set_show_tabs(False)
87 label = left('Checking: ' + interface.uri)
88 label.set_padding(4, 4)
89 vbox.pack_start(label, False, True, 0)
91 currently_trusted_keys = trust.trust_db.get_keys_for_domain(domain)
92 if currently_trusted_keys:
93 keys = [gpg.load_key(fingerprint) for fingerprint in currently_trusted_keys]
94 descriptions = ["%s\n(fingerprint: %s)" % (key.name, pretty_fp(key.fingerprint))
95 for key in keys]
96 else:
97 descriptions = ['None']
98 dialog.frame(vbox, 'Keys already approved for "%s"' % domain, '\n'.join(descriptions))
100 if len(self.valid_sigs) == 1:
101 label = left('This key signed the feed:')
102 else:
103 label = left('These keys signed the feed:')
105 label.set_padding(4, 4)
106 vbox.pack_start(label, False, True, 0)
108 vbox.pack_start(notebook, True, True, 0)
110 self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
111 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
112 self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
113 self.set_default_response(gtk.RESPONSE_OK)
115 trust_checkbox = {} # Sig -> CheckButton
116 def ok_sensitive():
117 trust_any = False
118 for toggle in trust_checkbox.values():
119 if toggle.get_active():
120 trust_any = True
121 break
122 self.set_response_sensitive(gtk.RESPONSE_OK, trust_any)
124 for sig in self.valid_sigs:
125 if hasattr(sig, 'get_details'):
126 name = '<unknown>'
127 details = sig.get_details()
128 for item in details:
129 if item[0] in ('pub', 'uid') and \
130 len(item) > 9:
131 name = item[9]
132 break
133 else:
134 name = None
135 page = gtk.VBox(False, 4)
136 page.set_border_width(8)
138 dialog.frame(page, 'Fingerprint', pretty_fp(sig.fingerprint))
140 if name is not None:
141 dialog.frame(page, 'Claimed identity', name)
143 hint = left(hints.get(sig.fingerprint, 'Warning: Nothing known about this key!'))
144 hint.set_line_wrap(True)
145 dialog.frame(page, 'Unreliable hints database says', hint)
147 already_trusted = trust.trust_db.get_trust_domains(sig.fingerprint)
148 if already_trusted:
149 dialog.frame(page, 'You already trust this key for these domains',
150 '\n'.join(already_trusted))
152 trust_checkbox[sig] = gtk.CheckButton('_Trust this key')
153 page.pack_start(trust_checkbox[sig], False, True, 0)
154 trust_checkbox[sig].connect('toggled', lambda t: ok_sensitive())
156 notebook.append_page(page, gtk.Label(name or 'Signature'))
158 ok_sensitive()
159 self.vbox.show_all()
161 def response(box, resp):
162 if resp == gtk.RESPONSE_HELP:
163 trust_help.display()
164 return
165 if resp == gtk.RESPONSE_OK:
166 self.trust_keys([sig for sig in trust_checkbox if trust_checkbox[sig].get_active()], domain)
167 self.destroy()
168 self.connect('response', response)
170 def trust_keys(self, sigs, domain):
171 assert domain
172 try:
173 for sig in sigs:
174 trust.trust_db.trust_key(sig.fingerprint, domain)
176 trust.trust_db.notify()
177 except Exception, ex:
178 dialog.alert(None, ex)
179 if not isinstance(ex, SafeException):
180 raise
182 _queue = []
183 def confirm_trust(interface, sigs, iface_xml, parent):
184 """Display a dialog box asking the user to confirm that one of the
185 keys is trusted for this domain. If a trust box is already visible, this
186 one is queued until the existing one is closed.
187 @param interface: the feed being loaded
188 @type interface: L{model.Interface}
189 @param sigs: the signatures on the feed
190 @type sigs: [L{gpg.Signature}]
191 @param iface_xml: the downloaded (untrusted) XML document
192 @type iface_xml: str
194 box = TrustBox(interface, sigs, iface_xml, parent)
195 _queue.append(box)
196 if len(_queue) == 1:
197 _queue[0].show()
198 return box.closed
200 trust_help = help_box.HelpBox("Trust Help",
201 ('Overview', """
202 When you run a program, it typically has access to all your files and can generally do \
203 anything that you're allowed to do (delete files, send emails, etc). So it's important \
204 to make sure that you don't run anything malicious."""),
206 ('Digital signatures', """
207 Each software author creates a 'key-pair'; a 'public key' and a 'private key'. Without going \
208 into the maths, only something encrypted with the private key will decrypt with the public key.
210 So, when a programmer releases some software, they encrypt it with their private key (which no-one \
211 else has). When you download it, the injector checks that it decrypts using their public key, thus \
212 proving that it came from them and hasn't been tampered with."""),
214 ('Trust', """
215 After the injector has checked that the software hasn't been modified since it was signed with \
216 the private key, you still have the following problems:
218 1. Does the public key you have really belong to the author?
219 2. Even if the software really did come from that person, do you trust them?"""),
221 ('Key fingerprints', """
222 To confirm (1), you should compare the public key you have with the genuine one. To make this \
223 easier, the injector displays a 'fingerprint' for the key. Look in mailing list postings or some \
224 other source to check that the fingerprint is right (a different key will have a different \
225 fingerprint).
227 You're trying to protect against the situation where an attacker breaks into a web site \
228 and puts up malicious software, signed with the attacker's private key, and puts up the \
229 attacker's public key too. If you've downloaded this software before, you \
230 should be suspicious that you're being asked to confirm another key!"""),
232 ('Reputation', """
233 In general, most problems seem to come from malicous and otherwise-unknown people \
234 replacing software with modified versions, or creating new programs intended only to \
235 cause damage. So, check your programs are signed by a key with a good reputation!"""))
237 hints = {
238 '1DC295D11A3F910DA49D3839AA1A7812B40B0B6E' :
239 'Ken Hayber has been writing ROX applications since 2003. This key '
240 'was announced on the rox-users list on 5 Jun 2005.',
242 '4338D5420E0BAEB6B2E73530B66A4F24AB8B4B65' :
243 'Thomas Formella is experimenting with packaging programs for 0launch. This key '
244 'was announced on 11 Sep 2005 on the zero-install mailing list.',
246 '92429807C9853C0744A68B9AAE07828059A53CC1' :
247 'Thomas Leonard created Zero Install and ROX. This key is used to sign updates to the '
248 'injector; you should accept it.',
250 '0597A2AFB6B372ACB97AC6E433B938C2E9D8826D' :
251 'Stephen Watson is a project admin for the ROX desktop, and has been involved with the '
252 'project since 2000. This key has been used for signing software since the 23 Jul 2005 '
253 'announcement on the zero-install mailing list.',
255 'F0A0CA2A8D8FCC123F5EC04CD8D59DC384AE988E' :
256 'Piero Ottuzzi is experimenting with packaging programs for 0launch. This key has been '
257 'known since a 16 Mar 2005 post to the zero-install mailing list. It was first used to '
258 'sign software in an announcement posted on 9 Aug 2005.',
260 'FC71DC3364367CE82F91472DDF32928893D894E9' :
261 'Niklas Höglund is experimenting with using Zero Install on the Nokia 770. This key has '
262 'been known since the announcement of 4 Apr 2006 on the zero-install mailing list.',
264 'B93AAE76C40A3222425A04FA0BDA706F2C21E592' :
265 'Ilja Honkonen is experimenting with packaging software for Zero Install. This key '
266 'was announced on 2006-04-21 on the zero-install mailing list.',
268 '5D3D90FB4E6FE10C7F76E94DEE6BC26DBFDE8022' :
269 'Dennis Tomas leads the rox4debian packaging effort. This key has been known since '
270 'an email forwarded to the rox-devel list on 2006-05-28.',
272 '2E2B4E59CAC8D874CD2759D34B1095AF2E992B19' :
273 'Lennon Cook creates the FreeBSD-x86 binaries for various ROX applications. '
274 'This key was announced in a Jun 17, 2006 post to the rox-devel mailing list.',
276 '7722DC5085B903FF176CCAA9695BA303C9839ABC' :
277 'Lennon Cook creates the FreeBSD-x86 binaries for various ROX applications. '
278 'This key was announced in an Oct 5, 2006 post to the rox-users mailing list.',
280 '03DC5771716A5A329CA97EA64AB8A8E7613A266F' :
281 'Lennon Cook creates the FreeBSD-x86 binaries for various ROX applications. '
282 'This key was announced in an Oct 7, 2007 post to the rox-users mailing list.',
284 '617794D7C3DFE0FFF572065C0529FDB71FB13910' :
285 'This low-security key is used to sign Zero Install interfaces which have been '
286 "automatically generated by a script. Typically, the upstream software didn't "
287 "come with a signature, so it's impossible to know if the code is actually OK. "
288 "However, there is still some benefit: if the archive is modified after the "
289 "script has signed it then any further changes will be detected, so this isn't "
290 "completely pointless.",
292 '5E665D0ECCCF1215F725BD2FA7421904E3D1B654' :
293 'Daniel Carrera works on the OpenDocument viewer from opendocumentfellowship.org. '
294 'This key was confirmed in a zero-install mailing list post on 2007-01-09.',
296 '635469E565B8D340C2C9EA4C32FBC18CE63EF486' :
297 'Eric Wasylishen is experimenting with packaging software with Zero Install. '
298 'This key was announced on the zero-install mailing list on 2007-01-16.',
300 'C82D382AAB381A54529019D6A0F9B035686C6996' :
301 "Justus Winter is generating Zero Install feeds from pkgsrc (which was originally "
302 "NetBSD's ports collection). This key was announced on the zero-install mailing list "
303 "on 2007-06-01.",
305 'D7582A2283A01A6480780AC8E1839306AE83E7E2' :
306 'Tom Adams is experimenting with packaging software with Zero Install. '
307 'This key was announced on the zero-install mailing list on 2007-08-14.',
309 '3B2A89E694686DC4FEEFD6F6D00CA21EC004251B' :
310 'Tuomo Valkonen is the author of the Ion tiling window manager. This key fingerprint '
311 'was taken from http://modeemi.fi/~tuomov/ on 2007-11-17.',
313 'A14924F4DFD1B81DED3436240C9B2C41B8D66FEA' :
314 'Andreas K. Förster is experimenting with creating Zero Install feeds. '
315 'This key was announced in a 2008-01-25 post to the zeroinstall mailing list.',
317 '520DCCDBE5D38E2B22ADD82672E5E2ACF037FFC4' :
318 'Thierry Goubier creates PPC binaries for the ROX desktop. This key was '
319 'announced in a 2008-02-03 posting to the rox-users list.'