|
1 // -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
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 XPCOMUtils.defineLazyModuleGetter(this, "LoadContextInfo", |
|
7 "resource://gre/modules/LoadContextInfo.jsm"); |
|
8 function Sanitizer() {} |
|
9 |
|
10 Sanitizer.prototype = { |
|
11 // warning to the caller: this one may raise an exception (e.g. bug #265028) |
|
12 clearItem: function (aItemName) |
|
13 { |
|
14 if (this.items[aItemName].canClear) |
|
15 this.items[aItemName].clear(); |
|
16 }, |
|
17 |
|
18 canClearItem: function (aItemName, aCallback, aArg) |
|
19 { |
|
20 let canClear = this.items[aItemName].canClear; |
|
21 if (typeof canClear == "function"){ |
|
22 canClear(aCallback, aArg); |
|
23 } else { |
|
24 aCallback(aItemName, canClear, aArg); |
|
25 } |
|
26 }, |
|
27 |
|
28 _prefDomain: "privacy.item.", |
|
29 getNameFromPreference: function (aPreferenceName) |
|
30 { |
|
31 return aPreferenceName.substr(this._prefDomain.length); |
|
32 }, |
|
33 |
|
34 /** |
|
35 * Deletes privacy sensitive data in a batch, according to user preferences |
|
36 * |
|
37 * @returns null if everything's fine; an object in the form |
|
38 * { itemName: error, ... } on (partial) failure |
|
39 */ |
|
40 sanitize: function () |
|
41 { |
|
42 var branch = Services.prefs.getBranch(this._prefDomain); |
|
43 var errors = null; |
|
44 for (var itemName in this.items) { |
|
45 if ("clear" in item && branch.getBoolPref(itemName)) { |
|
46 // Some of these clear() may raise exceptions (see bug #265028) |
|
47 // to sanitize as much as possible, we catch and store them, |
|
48 // rather than fail fast. |
|
49 // Callers should check returned errors and give user feedback |
|
50 // about items that could not be sanitized |
|
51 let clearCallback = (itemName, aCanClear) => { |
|
52 let item = this.items[itemName]; |
|
53 try{ |
|
54 if (aCanClear){ |
|
55 item.clear(); |
|
56 } |
|
57 } catch(er){ |
|
58 if (!errors){ |
|
59 errors = {}; |
|
60 } |
|
61 errors[itemName] = er; |
|
62 dump("Error sanitizing " + itemName + ":" + er + "\n"); |
|
63 } |
|
64 } |
|
65 this.canClearItem(itemName, clearCallback); |
|
66 } |
|
67 } |
|
68 return errors; |
|
69 }, |
|
70 |
|
71 items: { |
|
72 // Clear Sync account before passwords so that Sync still has access to the |
|
73 // credentials to clean up device-specific records on the server. Also |
|
74 // disable it before wiping history so we don't accidentally sync that. |
|
75 syncAccount: { |
|
76 clear: function () |
|
77 { |
|
78 Sync.disconnect(); |
|
79 }, |
|
80 |
|
81 get canClear() |
|
82 { |
|
83 return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED); |
|
84 } |
|
85 }, |
|
86 |
|
87 cache: { |
|
88 clear: function () |
|
89 { |
|
90 var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); |
|
91 try { |
|
92 cache.clear(); |
|
93 } catch(er) {} |
|
94 |
|
95 let imageCache = Cc["@mozilla.org/image/cache;1"].getService(Ci.imgICache); |
|
96 try { |
|
97 imageCache.clearCache(false); // true=chrome, false=content |
|
98 } catch(er) {} |
|
99 }, |
|
100 |
|
101 get canClear() |
|
102 { |
|
103 return true; |
|
104 } |
|
105 }, |
|
106 |
|
107 cookies: { |
|
108 clear: function () |
|
109 { |
|
110 var cookieMgr = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); |
|
111 cookieMgr.removeAll(); |
|
112 }, |
|
113 |
|
114 get canClear() |
|
115 { |
|
116 return true; |
|
117 } |
|
118 }, |
|
119 |
|
120 siteSettings: { |
|
121 clear: function () |
|
122 { |
|
123 // Clear site-specific permissions like "Allow this site to open popups" |
|
124 Services.perms.removeAll(); |
|
125 |
|
126 // Clear site-specific settings like page-zoom level |
|
127 var cps = Cc["@mozilla.org/content-pref/service;1"].getService(Ci.nsIContentPrefService2); |
|
128 cps.removeAllDomains(null); |
|
129 |
|
130 // Clear "Never remember passwords for this site", which is not handled by |
|
131 // the permission manager |
|
132 var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); |
|
133 var hosts = pwmgr.getAllDisabledHosts({}) |
|
134 for each (var host in hosts) { |
|
135 pwmgr.setLoginSavingEnabled(host, true); |
|
136 } |
|
137 }, |
|
138 |
|
139 get canClear() |
|
140 { |
|
141 return true; |
|
142 } |
|
143 }, |
|
144 |
|
145 offlineApps: { |
|
146 clear: function () |
|
147 { |
|
148 var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); |
|
149 var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null); |
|
150 try { |
|
151 appCacheStorage.asyncEvictStorage(null); |
|
152 } catch(er) {} |
|
153 }, |
|
154 |
|
155 get canClear() |
|
156 { |
|
157 return true; |
|
158 } |
|
159 }, |
|
160 |
|
161 history: { |
|
162 clear: function () |
|
163 { |
|
164 try { |
|
165 Services.obs.notifyObservers(null, "browser:purge-session-history", ""); |
|
166 } |
|
167 catch (e) { |
|
168 Components.utils.reportError("Failed to notify observers of " |
|
169 + "browser:purge-session-history: " |
|
170 + e); |
|
171 } |
|
172 }, |
|
173 |
|
174 get canClear() |
|
175 { |
|
176 // bug 347231: Always allow clearing history due to dependencies on |
|
177 // the browser:purge-session-history notification. (like error console) |
|
178 return true; |
|
179 } |
|
180 }, |
|
181 |
|
182 formdata: { |
|
183 clear: function () |
|
184 { |
|
185 //Clear undo history of all searchBars |
|
186 var windows = Services.wm.getEnumerator("navigator:browser"); |
|
187 while (windows.hasMoreElements()) { |
|
188 var searchBar = windows.getNext().document.getElementById("searchbar"); |
|
189 if (searchBar) { |
|
190 searchBar.value = ""; |
|
191 searchBar.textbox.editor.transactionManager.clear(); |
|
192 } |
|
193 } |
|
194 FormHistory.update({op : "remove"}); |
|
195 }, |
|
196 |
|
197 canClear : function(aCallback, aArg) |
|
198 { |
|
199 let count = 0; |
|
200 let countDone = { |
|
201 handleResult : function(aResult) { count = aResult; }, |
|
202 handleError : function(aError) { Components.utils.reportError(aError); }, |
|
203 handleCompletion : function(aReason) { aCallback("formdata", aReason == 0 && count > 0, aArg); } |
|
204 }; |
|
205 FormHistory.count({}, countDone); |
|
206 } |
|
207 }, |
|
208 |
|
209 downloads: { |
|
210 clear: function () |
|
211 { |
|
212 var dlMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); |
|
213 dlMgr.cleanUp(); |
|
214 }, |
|
215 |
|
216 get canClear() |
|
217 { |
|
218 var dlMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); |
|
219 return dlMgr.canCleanUp; |
|
220 } |
|
221 }, |
|
222 |
|
223 passwords: { |
|
224 clear: function () |
|
225 { |
|
226 var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); |
|
227 pwmgr.removeAllLogins(); |
|
228 }, |
|
229 |
|
230 get canClear() |
|
231 { |
|
232 var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); |
|
233 var count = pwmgr.countLogins("", "", ""); // count all logins |
|
234 return (count > 0); |
|
235 } |
|
236 }, |
|
237 |
|
238 sessions: { |
|
239 clear: function () |
|
240 { |
|
241 // clear all auth tokens |
|
242 var sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing); |
|
243 sdr.logoutAndTeardown(); |
|
244 |
|
245 // clear plain HTTP auth sessions |
|
246 var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].getService(Ci.nsIHttpAuthManager); |
|
247 authMgr.clearAll(); |
|
248 }, |
|
249 |
|
250 get canClear() |
|
251 { |
|
252 return true; |
|
253 } |
|
254 } |
|
255 } |
|
256 }; |
|
257 |
|
258 |
|
259 // "Static" members |
|
260 Sanitizer.prefDomain = "privacy.sanitize."; |
|
261 Sanitizer.prefShutdown = "sanitizeOnShutdown"; |
|
262 Sanitizer.prefDidShutdown = "didShutdownSanitize"; |
|
263 |
|
264 Sanitizer._prefs = null; |
|
265 Sanitizer.__defineGetter__("prefs", function() |
|
266 { |
|
267 return Sanitizer._prefs ? Sanitizer._prefs |
|
268 : Sanitizer._prefs = Cc["@mozilla.org/preferences-service;1"] |
|
269 .getService(Ci.nsIPrefService) |
|
270 .getBranch(Sanitizer.prefDomain); |
|
271 }); |
|
272 |
|
273 /** |
|
274 * Deletes privacy sensitive data in a batch, optionally showing the |
|
275 * sanitize UI, according to user preferences |
|
276 * |
|
277 * @returns null if everything's fine |
|
278 * an object in the form { itemName: error, ... } on (partial) failure |
|
279 */ |
|
280 Sanitizer.sanitize = function() |
|
281 { |
|
282 return new Sanitizer().sanitize(); |
|
283 }; |
|
284 |
|
285 Sanitizer.onStartup = function() |
|
286 { |
|
287 // we check for unclean exit with pending sanitization |
|
288 Sanitizer._checkAndSanitize(); |
|
289 }; |
|
290 |
|
291 Sanitizer.onShutdown = function() |
|
292 { |
|
293 // we check if sanitization is needed and perform it |
|
294 Sanitizer._checkAndSanitize(); |
|
295 }; |
|
296 |
|
297 // this is called on startup and shutdown, to perform pending sanitizations |
|
298 Sanitizer._checkAndSanitize = function() |
|
299 { |
|
300 const prefs = Sanitizer.prefs; |
|
301 if (prefs.getBoolPref(Sanitizer.prefShutdown) && |
|
302 !prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) { |
|
303 // this is a shutdown or a startup after an unclean exit |
|
304 Sanitizer.sanitize() || // sanitize() returns null on full success |
|
305 prefs.setBoolPref(Sanitizer.prefDidShutdown, true); |
|
306 } |
|
307 }; |
|
308 |
|
309 |