|
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 var security = { |
|
7 // Display the server certificate (static) |
|
8 viewCert : function () { |
|
9 var cert = security._cert; |
|
10 viewCertHelper(window, cert); |
|
11 }, |
|
12 |
|
13 _getSecurityInfo : function() { |
|
14 const nsIX509Cert = Components.interfaces.nsIX509Cert; |
|
15 const nsIX509CertDB = Components.interfaces.nsIX509CertDB; |
|
16 const nsX509CertDB = "@mozilla.org/security/x509certdb;1"; |
|
17 const nsISSLStatusProvider = Components.interfaces.nsISSLStatusProvider; |
|
18 const nsISSLStatus = Components.interfaces.nsISSLStatus; |
|
19 |
|
20 // We don't have separate info for a frame, return null until further notice |
|
21 // (see bug 138479) |
|
22 if (gWindow != gWindow.top) |
|
23 return null; |
|
24 |
|
25 var hName = null; |
|
26 try { |
|
27 hName = gWindow.location.host; |
|
28 } |
|
29 catch (exception) { } |
|
30 |
|
31 var ui = security._getSecurityUI(); |
|
32 if (!ui) |
|
33 return null; |
|
34 |
|
35 var isBroken = |
|
36 (ui.state & Components.interfaces.nsIWebProgressListener.STATE_IS_BROKEN); |
|
37 var isInsecure = |
|
38 (ui.state & Components.interfaces.nsIWebProgressListener.STATE_IS_INSECURE); |
|
39 var isEV = |
|
40 (ui.state & Components.interfaces.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL); |
|
41 ui.QueryInterface(nsISSLStatusProvider); |
|
42 var status = ui.SSLStatus; |
|
43 |
|
44 if (!isInsecure && status) { |
|
45 status.QueryInterface(nsISSLStatus); |
|
46 var cert = status.serverCert; |
|
47 var issuerName = |
|
48 this.mapIssuerOrganization(cert.issuerOrganization) || cert.issuerName; |
|
49 |
|
50 var retval = { |
|
51 hostName : hName, |
|
52 cAName : issuerName, |
|
53 encryptionAlgorithm : undefined, |
|
54 encryptionStrength : undefined, |
|
55 isBroken : isBroken, |
|
56 isEV : isEV, |
|
57 cert : cert, |
|
58 fullLocation : gWindow.location |
|
59 }; |
|
60 |
|
61 try { |
|
62 retval.encryptionAlgorithm = status.cipherName; |
|
63 retval.encryptionStrength = status.secretKeyLength; |
|
64 } |
|
65 catch (e) { |
|
66 } |
|
67 |
|
68 return retval; |
|
69 } else { |
|
70 return { |
|
71 hostName : hName, |
|
72 cAName : "", |
|
73 encryptionAlgorithm : "", |
|
74 encryptionStrength : 0, |
|
75 isBroken : isBroken, |
|
76 isEV : isEV, |
|
77 cert : null, |
|
78 fullLocation : gWindow.location |
|
79 }; |
|
80 } |
|
81 }, |
|
82 |
|
83 // Find the secureBrowserUI object (if present) |
|
84 _getSecurityUI : function() { |
|
85 if (window.opener.gBrowser) |
|
86 return window.opener.gBrowser.securityUI; |
|
87 return null; |
|
88 }, |
|
89 |
|
90 // Interface for mapping a certificate issuer organization to |
|
91 // the value to be displayed. |
|
92 // Bug 82017 - this implementation should be moved to pipnss C++ code |
|
93 mapIssuerOrganization: function(name) { |
|
94 if (!name) return null; |
|
95 |
|
96 if (name == "RSA Data Security, Inc.") return "Verisign, Inc."; |
|
97 |
|
98 // No mapping required |
|
99 return name; |
|
100 }, |
|
101 |
|
102 /** |
|
103 * Open the cookie manager window |
|
104 */ |
|
105 viewCookies : function() |
|
106 { |
|
107 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] |
|
108 .getService(Components.interfaces.nsIWindowMediator); |
|
109 var win = wm.getMostRecentWindow("Browser:Cookies"); |
|
110 var eTLDService = Components.classes["@mozilla.org/network/effective-tld-service;1"]. |
|
111 getService(Components.interfaces.nsIEffectiveTLDService); |
|
112 |
|
113 var eTLD; |
|
114 var uri = gDocument.documentURIObject; |
|
115 try { |
|
116 eTLD = eTLDService.getBaseDomain(uri); |
|
117 } |
|
118 catch (e) { |
|
119 // getBaseDomain will fail if the host is an IP address or is empty |
|
120 eTLD = uri.asciiHost; |
|
121 } |
|
122 |
|
123 if (win) { |
|
124 win.gCookiesWindow.setFilter(eTLD); |
|
125 win.focus(); |
|
126 } |
|
127 else |
|
128 window.openDialog("chrome://browser/content/preferences/cookies.xul", |
|
129 "Browser:Cookies", "", {filterString : eTLD}); |
|
130 }, |
|
131 |
|
132 /** |
|
133 * Open the login manager window |
|
134 */ |
|
135 viewPasswords : function() |
|
136 { |
|
137 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] |
|
138 .getService(Components.interfaces.nsIWindowMediator); |
|
139 var win = wm.getMostRecentWindow("Toolkit:PasswordManager"); |
|
140 if (win) { |
|
141 win.setFilter(this._getSecurityInfo().hostName); |
|
142 win.focus(); |
|
143 } |
|
144 else |
|
145 window.openDialog("chrome://passwordmgr/content/passwordManager.xul", |
|
146 "Toolkit:PasswordManager", "", |
|
147 {filterString : this._getSecurityInfo().hostName}); |
|
148 }, |
|
149 |
|
150 _cert : null |
|
151 }; |
|
152 |
|
153 function securityOnLoad() { |
|
154 var info = security._getSecurityInfo(); |
|
155 if (!info) { |
|
156 document.getElementById("securityTab").hidden = true; |
|
157 document.getElementById("securityBox").collapsed = true; |
|
158 return; |
|
159 } |
|
160 else { |
|
161 document.getElementById("securityTab").hidden = false; |
|
162 document.getElementById("securityBox").collapsed = false; |
|
163 } |
|
164 |
|
165 const pageInfoBundle = document.getElementById("pageinfobundle"); |
|
166 |
|
167 /* Set Identity section text */ |
|
168 setText("security-identity-domain-value", info.hostName); |
|
169 |
|
170 var owner, verifier, generalPageIdentityString; |
|
171 if (info.cert && !info.isBroken) { |
|
172 // Try to pull out meaningful values. Technically these fields are optional |
|
173 // so we'll employ fallbacks where appropriate. The EV spec states that Org |
|
174 // fields must be specified for subject and issuer so that case is simpler. |
|
175 if (info.isEV) { |
|
176 owner = info.cert.organization; |
|
177 verifier = security.mapIssuerOrganization(info.cAName); |
|
178 generalPageIdentityString = pageInfoBundle.getFormattedString("generalSiteIdentity", |
|
179 [owner, verifier]); |
|
180 } |
|
181 else { |
|
182 // Technically, a non-EV cert might specify an owner in the O field or not, |
|
183 // depending on the CA's issuing policies. However we don't have any programmatic |
|
184 // way to tell those apart, and no policy way to establish which organization |
|
185 // vetting standards are good enough (that's what EV is for) so we default to |
|
186 // treating these certs as domain-validated only. |
|
187 owner = pageInfoBundle.getString("securityNoOwner"); |
|
188 verifier = security.mapIssuerOrganization(info.cAName || |
|
189 info.cert.issuerCommonName || |
|
190 info.cert.issuerName); |
|
191 generalPageIdentityString = owner; |
|
192 } |
|
193 } |
|
194 else { |
|
195 // We don't have valid identity credentials. |
|
196 owner = pageInfoBundle.getString("securityNoOwner"); |
|
197 verifier = pageInfoBundle.getString("notset"); |
|
198 generalPageIdentityString = owner; |
|
199 } |
|
200 |
|
201 setText("security-identity-owner-value", owner); |
|
202 setText("security-identity-verifier-value", verifier); |
|
203 setText("general-security-identity", generalPageIdentityString); |
|
204 |
|
205 /* Manage the View Cert button*/ |
|
206 var viewCert = document.getElementById("security-view-cert"); |
|
207 if (info.cert) { |
|
208 security._cert = info.cert; |
|
209 viewCert.collapsed = false; |
|
210 } |
|
211 else |
|
212 viewCert.collapsed = true; |
|
213 |
|
214 /* Set Privacy & History section text */ |
|
215 var yesStr = pageInfoBundle.getString("yes"); |
|
216 var noStr = pageInfoBundle.getString("no"); |
|
217 |
|
218 var uri = gDocument.documentURIObject; |
|
219 setText("security-privacy-cookies-value", |
|
220 hostHasCookies(uri) ? yesStr : noStr); |
|
221 setText("security-privacy-passwords-value", |
|
222 realmHasPasswords(uri) ? yesStr : noStr); |
|
223 |
|
224 var visitCount = previousVisitCount(info.hostName); |
|
225 if(visitCount > 1) { |
|
226 setText("security-privacy-history-value", |
|
227 pageInfoBundle.getFormattedString("securityNVisits", [visitCount.toLocaleString()])); |
|
228 } |
|
229 else if (visitCount == 1) { |
|
230 setText("security-privacy-history-value", |
|
231 pageInfoBundle.getString("securityOneVisit")); |
|
232 } |
|
233 else { |
|
234 setText("security-privacy-history-value", noStr); |
|
235 } |
|
236 |
|
237 /* Set the Technical Detail section messages */ |
|
238 const pkiBundle = document.getElementById("pkiBundle"); |
|
239 var hdr; |
|
240 var msg1; |
|
241 var msg2; |
|
242 |
|
243 if (info.isBroken) { |
|
244 hdr = pkiBundle.getString("pageInfo_MixedContent"); |
|
245 msg1 = pkiBundle.getString("pageInfo_Privacy_Mixed1"); |
|
246 msg2 = pkiBundle.getString("pageInfo_Privacy_None2"); |
|
247 } |
|
248 else if (info.encryptionStrength >= 90) { |
|
249 hdr = pkiBundle.getFormattedString("pageInfo_StrongEncryptionWithBits", |
|
250 [info.encryptionAlgorithm, info.encryptionStrength + ""]); |
|
251 msg1 = pkiBundle.getString("pageInfo_Privacy_Strong1"); |
|
252 msg2 = pkiBundle.getString("pageInfo_Privacy_Strong2"); |
|
253 security._cert = info.cert; |
|
254 } |
|
255 else if (info.encryptionStrength > 0) { |
|
256 hdr = pkiBundle.getFormattedString("pageInfo_WeakEncryptionWithBits", |
|
257 [info.encryptionAlgorithm, info.encryptionStrength + ""]); |
|
258 msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_Weak1", [info.hostName]); |
|
259 msg2 = pkiBundle.getString("pageInfo_Privacy_Weak2"); |
|
260 } |
|
261 else { |
|
262 hdr = pkiBundle.getString("pageInfo_NoEncryption"); |
|
263 if (info.hostName != null) |
|
264 msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]); |
|
265 else |
|
266 msg1 = pkiBundle.getString("pageInfo_Privacy_None3"); |
|
267 msg2 = pkiBundle.getString("pageInfo_Privacy_None2"); |
|
268 } |
|
269 setText("security-technical-shortform", hdr); |
|
270 setText("security-technical-longform1", msg1); |
|
271 setText("security-technical-longform2", msg2); |
|
272 setText("general-security-privacy", hdr); |
|
273 } |
|
274 |
|
275 function setText(id, value) |
|
276 { |
|
277 var element = document.getElementById(id); |
|
278 if (!element) |
|
279 return; |
|
280 if (element.localName == "textbox" || element.localName == "label") |
|
281 element.value = value; |
|
282 else { |
|
283 if (element.hasChildNodes()) |
|
284 element.removeChild(element.firstChild); |
|
285 var textNode = document.createTextNode(value); |
|
286 element.appendChild(textNode); |
|
287 } |
|
288 } |
|
289 |
|
290 function viewCertHelper(parent, cert) |
|
291 { |
|
292 if (!cert) |
|
293 return; |
|
294 |
|
295 var cd = Components.classes[CERTIFICATEDIALOGS_CONTRACTID].getService(nsICertificateDialogs); |
|
296 cd.viewCert(parent, cert); |
|
297 } |
|
298 |
|
299 /** |
|
300 * Return true iff we have cookies for uri |
|
301 */ |
|
302 function hostHasCookies(uri) { |
|
303 var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"] |
|
304 .getService(Components.interfaces.nsICookieManager2); |
|
305 |
|
306 return cookieManager.countCookiesFromHost(uri.asciiHost) > 0; |
|
307 } |
|
308 |
|
309 /** |
|
310 * Return true iff realm (proto://host:port) (extracted from uri) has |
|
311 * saved passwords |
|
312 */ |
|
313 function realmHasPasswords(uri) { |
|
314 var passwordManager = Components.classes["@mozilla.org/login-manager;1"] |
|
315 .getService(Components.interfaces.nsILoginManager); |
|
316 return passwordManager.countLogins(uri.prePath, "", "") > 0; |
|
317 } |
|
318 |
|
319 /** |
|
320 * Return the number of previous visits recorded for host before today. |
|
321 * |
|
322 * @param host - the domain name to look for in history |
|
323 */ |
|
324 function previousVisitCount(host, endTimeReference) { |
|
325 if (!host) |
|
326 return false; |
|
327 |
|
328 var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"] |
|
329 .getService(Components.interfaces.nsINavHistoryService); |
|
330 |
|
331 var options = historyService.getNewQueryOptions(); |
|
332 options.resultType = options.RESULTS_AS_VISIT; |
|
333 |
|
334 // Search for visits to this host before today |
|
335 var query = historyService.getNewQuery(); |
|
336 query.endTimeReference = query.TIME_RELATIVE_TODAY; |
|
337 query.endTime = 0; |
|
338 query.domain = host; |
|
339 |
|
340 var result = historyService.executeQuery(query, options); |
|
341 result.root.containerOpen = true; |
|
342 var cc = result.root.childCount; |
|
343 result.root.containerOpen = false; |
|
344 return cc; |
|
345 } |