1 # -*- coding: utf-8 -*-
4 from zeroinstall
.injector
.model
import SafeException
5 from zeroinstall
.injector
import gpg
, trust
6 from zeroinstall
.injector
.iface_cache
import iface_cache
9 import dialog
, help_box
13 for x
in range(4, len(fp
), 4):
14 s
+= ' ' + fp
[x
:x
+ 4]
17 class TrustBox(dialog
.Dialog
):
23 def __init__(self
, interface
, sigs
, iface_xml
):
24 dialog
.Dialog
.__init
__(self
)
26 domain
= trust
.domain_from_url(interface
.uri
)
31 assert _queue
[0] is self
33 # Remove any queued boxes that are no longer required
34 def still_untrusted(box
):
35 for sig
in box
.valid_sigs
:
36 is_trusted
= trust
.trust_db
.is_trusted(sig
.fingerprint
, domain
)
42 if still_untrusted(next
):
45 next
.trust_keys([], domain
)
46 next
.destroy() # Will trigger this again...
47 self
.connect('destroy', destroy
)
50 label
= gtk
.Label(text
)
51 label
.set_alignment(0, 0.5)
52 label
.set_selectable(True)
55 self
.interface
= interface
57 self
.iface_xml
= iface_xml
59 self
.set_title('Confirm trust')
61 vbox
= gtk
.VBox(False, 4)
62 vbox
.set_border_width(4)
63 self
.vbox
.pack_start(vbox
, True, True, 0)
65 self
.valid_sigs
= [s
for s
in sigs
if isinstance(s
, gpg
.ValidSig
)]
66 if not self
.valid_sigs
:
67 raise SafeException('No valid signatures found. Signatures:' +
68 ''.join(['\n- ' + str(s
) for s
in sigs
]))
70 notebook
= gtk
.Notebook()
72 if len(self
.valid_sigs
) == 1:
73 notebook
.set_show_tabs(False)
75 label
= left('Checking: ' + interface
.uri
)
76 label
.set_padding(4, 4)
77 vbox
.pack_start(label
, False, True, 0)
79 currently_trusted_keys
= trust
.trust_db
.get_keys_for_domain(domain
)
80 if currently_trusted_keys
:
81 keys
= [gpg
.load_key(fingerprint
) for fingerprint
in currently_trusted_keys
]
82 descriptions
= ["%s\n(fingerprint: %s)" % (key
.name
, pretty_fp(key
.fingerprint
))
85 descriptions
= ['None']
86 dialog
.frame(vbox
, 'Keys already approved for "%s"' % domain
, '\n'.join(descriptions
))
88 if len(self
.valid_sigs
) == 1:
89 label
= left('This key signed the feed:')
91 label
= left('These keys signed the feed:')
93 label
.set_padding(4, 4)
94 vbox
.pack_start(label
, False, True, 0)
96 vbox
.pack_start(notebook
, True, True, 0)
98 self
.add_button(gtk
.STOCK_HELP
, gtk
.RESPONSE_HELP
)
99 self
.add_button(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
)
100 self
.add_button(gtk
.STOCK_ADD
, gtk
.RESPONSE_OK
)
101 self
.set_default_response(gtk
.RESPONSE_OK
)
103 trust_checkbox
= {} # Sig -> CheckButton
106 for toggle
in trust_checkbox
.values():
107 if toggle
.get_active():
110 self
.set_response_sensitive(gtk
.RESPONSE_OK
, trust_any
)
112 for sig
in self
.valid_sigs
:
113 if hasattr(sig
, 'get_details'):
115 details
= sig
.get_details()
117 if item
[0] in ('pub', 'uid') and \
123 page
= gtk
.VBox(False, 4)
124 page
.set_border_width(8)
126 dialog
.frame(page
, 'Fingerprint', pretty_fp(sig
.fingerprint
))
129 dialog
.frame(page
, 'Claimed identity', name
)
131 hint
= left(hints
.get(sig
.fingerprint
, 'Warning: Nothing known about this key!'))
132 hint
.set_line_wrap(True)
133 dialog
.frame(page
, 'Unreliable hints database says', hint
)
135 already_trusted
= trust
.trust_db
.get_trust_domains(sig
.fingerprint
)
137 dialog
.frame(page
, 'You already trust this key for these domains',
138 '\n'.join(already_trusted
))
140 trust_checkbox
[sig
] = gtk
.CheckButton('_Trust this key')
141 page
.pack_start(trust_checkbox
[sig
], False, True, 0)
142 trust_checkbox
[sig
].connect('toggled', lambda t
: ok_sensitive())
144 notebook
.append_page(page
, gtk
.Label(name
or 'Signature'))
149 def response(box
, resp
):
150 if resp
== gtk
.RESPONSE_HELP
:
153 if resp
== gtk
.RESPONSE_OK
:
154 self
.trust_keys([sig
for sig
in trust_checkbox
if trust_checkbox
[sig
].get_active()], domain
)
156 self
.connect('response', response
)
158 def trust_keys(self
, sigs
, domain
):
162 trust
.trust_db
.trust_key(sig
.fingerprint
, domain
)
164 trust
.trust_db
.notify()
165 except Exception, ex
:
166 dialog
.alert(None, ex
)
167 if not isinstance(ex
, SafeException
):
171 def confirm_trust(interface
, sigs
, iface_xml
):
172 """Display a dialog box asking the user to confirm that one of the
173 keys is trusted for this domain. If a trust box is already visible, this
174 one is queued until the existing one is closed.
175 @param interface: the feed being loaded
176 @type interface: L{model.Interface}
177 @param sigs: the signatures on the feed
178 @type sigs: [L{gpg.Signature}]
179 @param iface_xml: the downloaded (untrusted) XML document
182 _queue
.append(TrustBox(interface
, sigs
, iface_xml
))
186 trust_help
= help_box
.HelpBox("Trust Help",
188 When you run a program, it typically has access to all your files and can generally do \
189 anything that you're allowed to do (delete files, send emails, etc). So it's important \
190 to make sure that you don't run anything malicious."""),
192 ('Digital signatures', """
193 Each software author creates a 'key-pair'; a 'public key' and a 'private key'. Without going \
194 into the maths, only something encrypted with the private key will decrypt with the public key.
196 So, when a programmer releases some software, they encrypt it with their private key (which no-one \
197 else has). When you download it, the injector checks that it decrypts using their public key, thus \
198 proving that it came from them and hasn't been tampered with."""),
201 After the injector has checked that the software hasn't been modified since it was signed with \
202 the private key, you still have the following problems:
204 1. Does the public key you have really belong to the author?
205 2. Even if the software really did come from that person, do you trust them?"""),
207 ('Key fingerprints', """
208 To confirm (1), you should compare the public key you have with the genuine one. To make this \
209 easier, the injector displays a 'fingerprint' for the key. Look in mailing list postings or some \
210 other source to check that the fingerprint is right (a different key will have a different \
213 You're trying to protect against the situation where an attacker breaks into a web site \
214 and puts up malicious software, signed with the attacker's private key, and puts up the \
215 attacker's public key too. If you've downloaded this software before, you \
216 should be suspicious that you're being asked to confirm another key!"""),
219 In general, most problems seem to come from malicous and otherwise-unknown people \
220 replacing software with modified versions, or creating new programs intended only to \
221 cause damage. So, check your programs are signed by a key with a good reputation!"""))
224 '1DC295D11A3F910DA49D3839AA1A7812B40B0B6E' :
225 'Ken Hayber has been writing ROX applications since 2003. This key '
226 'was announced on the rox-users list on 5 Jun 2005.',
228 '4338D5420E0BAEB6B2E73530B66A4F24AB8B4B65' :
229 'Thomas Formella is experimenting with packaging programs for 0launch. This key '
230 'was announced on 11 Sep 2005 on the zero-install mailing list.',
232 '92429807C9853C0744A68B9AAE07828059A53CC1' :
233 'Thomas Leonard created Zero Install and ROX. This key is used to sign updates to the '
234 'injector; you should accept it.',
236 '0597A2AFB6B372ACB97AC6E433B938C2E9D8826D' :
237 'Stephen Watson is a project admin for the ROX desktop, and has been involved with the '
238 'project since 2000. This key has been used for signing software since the 23 Jul 2005 '
239 'announcement on the zero-install mailing list.',
241 'F0A0CA2A8D8FCC123F5EC04CD8D59DC384AE988E' :
242 'Piero Ottuzzi is experimenting with packaging programs for 0launch. This key has been '
243 'known since a 16 Mar 2005 post to the zero-install mailing list. It was first used to '
244 'sign software in an announcement posted on 9 Aug 2005.',
246 'FC71DC3364367CE82F91472DDF32928893D894E9' :
247 'Niklas Höglund is experimenting with using Zero Install on the Nokia 770. This key has '
248 'been known since the announcement of 4 Apr 2006 on the zero-install mailing list.',
250 'B93AAE76C40A3222425A04FA0BDA706F2C21E592' :
251 'Ilja Honkonen is experimenting with packaging software for Zero Install. This key '
252 'was announced on 2006-04-21 on the zero-install mailing list.',
254 '5D3D90FB4E6FE10C7F76E94DEE6BC26DBFDE8022' :
255 'Dennis Tomas leads the rox4debian packaging effort. This key has been known since '
256 'an email forwarded to the rox-devel list on 2006-05-28.',
258 '2E2B4E59CAC8D874CD2759D34B1095AF2E992B19' :
259 'Lennon Cook creates the FreeBSD-x86 binaries for various ROX applications. '
260 'This key was announced in a Jun 17, 2006 post to the rox-devel mailing list.',
262 '7722DC5085B903FF176CCAA9695BA303C9839ABC' :
263 'Lennon Cook creates the FreeBSD-x86 binaries for various ROX applications. '
264 'This key was announced in an Oct 5, 2006 post to the rox-users mailing list.',
266 '617794D7C3DFE0FFF572065C0529FDB71FB13910' :
267 'This low-security key is used to sign Zero Install interfaces which have been '
268 "automatically generated by a script. Typically, the upstream software didn't "
269 "come with a signature, so it's impossible to know if the code is actually OK. "
270 "However, there is still some benefit: if the archive is modified after the "
271 "script has signed it then any further changes will be detected, so this isn't "
272 "completely pointless.",
274 '5E665D0ECCCF1215F725BD2FA7421904E3D1B654' :
275 'Daniel Carrera works on the OpenDocument viewer from opendocumentfellowship.org. '
276 'This key was confirmed in a zero-install mailing list post on 2007-01-09.',
278 '635469E565B8D340C2C9EA4C32FBC18CE63EF486' :
279 'Eric Wasylishen is experimenting with packaging software with Zero Install. '
280 'This key was announced on the zero-install mailing list on 2007-01-16.',
282 'C82D382AAB381A54529019D6A0F9B035686C6996' :
283 "Justus Winter is generating Zero Install feeds from pkgsrc (which was originally "
284 "NetBSD's ports collection). This key was announced on the zero-install mailing list "