sanitize.js
Go to the documentation of this file.
1 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 #
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
9 #
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
13 # License.
14 #
15 # The Original Code is the Firefox Sanitizer.
16 #
17 # The Initial Developer of the Original Code is
18 # Ben Goodger.
19 # Portions created by the Initial Developer are Copyright (C) 2005
20 # the Initial Developer. All Rights Reserved.
21 #
22 # Contributor(s):
23 # Ben Goodger <ben@mozilla.org>
24 # Giorgio Maone <g.maone@informaction.com>
25 # Johnathan Nightingale <johnath@mozilla.com>
26 # Ehsan Akhgari <ehsan.akhgari@gmail.com>
27 #
28 # Alternatively, the contents of this file may be used under the terms of
29 # either the GNU General Public License Version 2 or later (the "GPL"), or
30 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 # in which case the provisions of the GPL or the LGPL are applicable instead
32 # of those above. If you wish to allow use of your version of this file only
33 # under the terms of either the GPL or the LGPL, and not to allow others to
34 # use your version of this file under the terms of the MPL, indicate your
35 # decision by deleting the provisions above and replace them with the notice
36 # and other provisions required by the GPL or the LGPL. If you do not delete
37 # the provisions above, a recipient may use your version of this file under
38 # the terms of any one of the MPL, the GPL or the LGPL.
39 #
40 # ***** END LICENSE BLOCK *****
41 
42 function Sanitizer() {}
43 Sanitizer.prototype = {
44  // warning to the caller: this one may raise an exception (e.g. bug #265028)
45  clearItem: function (aItemName)
46  {
47  if (this.items[aItemName].canClear)
48  this.items[aItemName].clear();
49  },
50 
51  canClearItem: function (aItemName)
52  {
53  return this.items[aItemName].canClear;
54  },
55 
56  prefDomain: "",
57 
58  getNameFromPreference: function (aPreferenceName)
59  {
60  return aPreferenceName.substr(this.prefDomain.length);
61  },
62 
69  sanitize: function ()
70  {
71  var psvc = Components.classes["@mozilla.org/preferences-service;1"]
72  .getService(Components.interfaces.nsIPrefService);
73  var branch = psvc.getBranch(this.prefDomain);
74  var errors = null;
75 
76  // Cache the range of times to clear
77  if (this.ignoreTimespan)
78  var range = null; // If we ignore timespan, clear everything
79  else
80  range = this.range || Sanitizer.getClearRange();
81 
82  for (var itemName in this.items) {
83  var item = this.items[itemName];
84  item.range = range;
85  if ("clear" in item && item.canClear && branch.getBoolPref(itemName)) {
86  // Some of these clear() may raise exceptions (see bug #265028)
87  // to sanitize as much as possible, we catch and store them,
88  // rather than fail fast.
89  // Callers should check returned errors and give user feedback
90  // about items that could not be sanitized
91  try {
92  item.clear();
93  } catch(er) {
94  if (!errors)
95  errors = {};
96  errors[itemName] = er;
97  dump("Error sanitizing " + itemName + ": " + er + "\n");
98  }
99  }
100  }
101  return errors;
102  },
103 
104  // Time span only makes sense in certain cases. Consumers who want
105  // to only clear some private data can opt in by setting this to false,
106  // and can optionally specify a specific range. If timespan is not ignored,
107  // and range is not set, sanitize() will use the value of the timespan
108  // pref to determine a range
109  ignoreTimespan : true,
110  range : null,
111 
112  items: {
113  cache: {
114  clear: function ()
115  {
116  const Cc = Components.classes;
117  const Ci = Components.interfaces;
118  var cacheService = Cc["@mozilla.org/network/cache-service;1"].
119  getService(Ci.nsICacheService);
120  try {
121  // Cache doesn't consult timespan, nor does it have the
122  // facility for timespan-based eviction. Wipe it.
123  cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
124  } catch(er) {}
125  },
126 
127  get canClear()
128  {
129  return true;
130  }
131  },
132 
133  cookies: {
134  clear: function ()
135  {
136  const Ci = Components.interfaces;
137  var cookieMgr = Components.classes["@mozilla.org/cookiemanager;1"]
138  .getService(Ci.nsICookieManager);
139  if (this.range) {
140  // Iterate through the cookies and delete any created after our cutoff.
141  var cookiesEnum = cookieMgr.enumerator;
142  while (cookiesEnum.hasMoreElements()) {
143  var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
144 
145  if (cookie.creationTime > this.range[0])
146  // This cookie was created after our cutoff, clear it
147  cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
148  }
149  }
150  else {
151  // Remove everything
152  cookieMgr.removeAll();
153  }
154 
155  // clear any network geolocation provider sessions
156  var psvc = Components.classes["@mozilla.org/preferences-service;1"]
157  .getService(Components.interfaces.nsIPrefService);
158  try {
159  var branch = psvc.getBranch("geo.wifi.access_token.");
160  branch.deleteBranch("");
161  } catch (e) {}
162 
163  },
164 
165  get canClear()
166  {
167  return true;
168  }
169  },
170 
171  offlineApps: {
172  clear: function ()
173  {
174  const Cc = Components.classes;
175  const Ci = Components.interfaces;
176  var cacheService = Cc["@mozilla.org/network/cache-service;1"].
177  getService(Ci.nsICacheService);
178  try {
179  // Offline app data is "timeless", and doesn't respect
180  // the setting of timespan, it always clears everything
181  cacheService.evictEntries(Ci.nsICache.STORE_OFFLINE);
182  } catch(er) {}
183 
184  var storageManagerService = Cc["@mozilla.org/dom/storagemanager;1"].
185  getService(Ci.nsIDOMStorageManager);
186  storageManagerService.clearOfflineApps();
187  },
188 
189  get canClear()
190  {
191  return true;
192  }
193  },
194 
195  history: {
196  clear: function ()
197  {
198  var globalHistory = Components.classes["@mozilla.org/browser/global-history;2"]
199  .getService(Components.interfaces.nsIBrowserHistory);
200  if (this.range)
201  globalHistory.removeVisitsByTimeframe(this.range[0], this.range[1]);
202  else
203  globalHistory.removeAllPages();
204 
205  try {
206  var os = Components.classes["@mozilla.org/observer-service;1"]
207  .getService(Components.interfaces.nsIObserverService);
208  os.notifyObservers(null, "browser:purge-session-history", "");
209  }
210  catch (e) { }
211 
212  // Clear last URL of the Open Web Location dialog
213  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
214  .getService(Components.interfaces.nsIPrefBranch2);
215  try {
216  prefs.clearUserPref("general.open_location.last_url");
217  }
218  catch (e) { }
219  },
220 
221  get canClear()
222  {
223  // bug 347231: Always allow clearing history due to dependencies on
224  // the browser:purge-session-history notification. (like error console)
225  return true;
226  }
227  },
228 
229  formdata: {
230  clear: function ()
231  {
232  // Clear undo history of all searchBars
233  var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
234  .getService(Components.interfaces.nsIWindowMediator);
235  var windows = windowManager.getEnumerator("navigator:browser");
236  while (windows.hasMoreElements()) {
237  var searchBar = windows.getNext().document.getElementById("searchbar");
238  if (searchBar)
239  searchBar.textbox.reset();
240  }
241 
242  var formHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
243  .getService(Components.interfaces.nsIFormHistory2);
244  if (this.range)
245  formHistory.removeEntriesByTimeframe(this.range[0], this.range[1]);
246  else
247  formHistory.removeAllEntries();
248  },
249 
250  get canClear()
251  {
252  var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
253  .getService(Components.interfaces.nsIWindowMediator);
254  var windows = windowManager.getEnumerator("navigator:browser");
255  while (windows.hasMoreElements()) {
256  var searchBar = windows.getNext().document.getElementById("searchbar");
257  if (searchBar) {
258  var transactionMgr = searchBar.textbox.editor.transactionManager;
259  if (searchBar.value ||
260  transactionMgr.numberOfUndoItems ||
261  transactionMgr.numberOfRedoItems)
262  return true;
263  }
264  }
265 
266  var formHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
267  .getService(Components.interfaces.nsIFormHistory2);
268  return formHistory.hasEntries;
269  }
270  },
271 
272  downloads: {
273  clear: function ()
274  {
275  var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
276  .getService(Components.interfaces.nsIDownloadManager);
277 
278  var dlIDsToRemove = [];
279  if (this.range) {
280  // First, remove the completed/cancelled downloads
281  dlMgr.removeDownloadsByTimeframe(this.range[0], this.range[1]);
282 
283  // Queue up any active downloads that started in the time span as well
284  var dlsEnum = dlMgr.activeDownloads;
285  while(dlsEnum.hasMoreElements()) {
286  var dl = dlsEnum.next();
287  if(dl.startTime >= this.range[0])
288  dlIDsToRemove.push(dl.id);
289  }
290  }
291  else {
292  // Clear all completed/cancelled downloads
293  dlMgr.cleanUp();
294 
295  // Queue up all active ones as well
296  var dlsEnum = dlMgr.activeDownloads;
297  while(dlsEnum.hasMoreElements()) {
298  dlIDsToRemove.push(dlsEnum.next().id);
299  }
300  }
301 
302  // Remove any queued up active downloads
303  dlIDsToRemove.forEach(function(id) {
304  dlMgr.removeDownload(id);
305  });
306  },
307 
308  get canClear()
309  {
310  var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
311  .getService(Components.interfaces.nsIDownloadManager);
312  return dlMgr.canCleanUp;
313  }
314  },
315 
316  passwords: {
317  clear: function ()
318  {
319  var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
320  .getService(Components.interfaces.nsILoginManager);
321  // Passwords are timeless, and don't respect the timeSpan setting
322  pwmgr.removeAllLogins();
323  },
324 
325  get canClear()
326  {
327  var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
328  .getService(Components.interfaces.nsILoginManager);
329  var count = pwmgr.countLogins("", "", ""); // count all logins
330  return (count > 0);
331  }
332  },
333 
334  sessions: {
335  clear: function ()
336  {
337  // clear all auth tokens
338  var sdr = Components.classes["@mozilla.org/security/sdr;1"]
339  .getService(Components.interfaces.nsISecretDecoderRing);
340  sdr.logoutAndTeardown();
341 
342  // clear FTP and plain HTTP auth sessions
343  var os = Components.classes["@mozilla.org/observer-service;1"]
344  .getService(Components.interfaces.nsIObserverService);
345  os.notifyObservers(null, "net:clear-active-logins", null);
346  },
347 
348  get canClear()
349  {
350  return true;
351  }
352  },
353 
354  siteSettings: {
355  clear: function ()
356  {
357  // Clear site-specific permissions like "Allow this site to open popups"
358  var pm = Components.classes["@mozilla.org/permissionmanager;1"]
359  .getService(Components.interfaces.nsIPermissionManager);
360  pm.removeAll();
361 
362  // Clear site-specific settings like page-zoom level
363  var cps = Components.classes["@mozilla.org/content-pref/service;1"]
364  .getService(Components.interfaces.nsIContentPrefService);
365  cps.removeGroupedPrefs();
366 
367  // Clear "Never remember passwords for this site", which is not handled by
368  // the permission manager
369  var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
370  .getService(Components.interfaces.nsILoginManager);
371  var hosts = pwmgr.getAllDisabledHosts({})
372  for each (var host in hosts) {
373  pwmgr.setLoginSavingEnabled(host, true);
374  }
375  },
376 
377  get canClear()
378  {
379  return true;
380  }
381  }
382  }
383 };
384 
385 
386 
387 // "Static" members
388 Sanitizer.prefDomain = "privacy.sanitize.";
389 Sanitizer.prefShutdown = "sanitizeOnShutdown";
390 Sanitizer.prefDidShutdown = "didShutdownSanitize";
391 
392 // Time span constants corresponding to values of the privacy.sanitize.timeSpan
393 // pref. Used to determine how much history to clear, for various items
394 Sanitizer.TIMESPAN_EVERYTHING = 0;
395 Sanitizer.TIMESPAN_HOUR = 1;
396 Sanitizer.TIMESPAN_2HOURS = 2;
397 Sanitizer.TIMESPAN_4HOURS = 3;
398 Sanitizer.TIMESPAN_TODAY = 4;
399 
400 // Return a 2 element array representing the start and end times,
401 // in the uSec-since-epoch format that PRTime likes. If we should
402 // clear everything, return null. Use ts if it is defined; otherwise
403 // use the timeSpan pref.
404 Sanitizer.getClearRange = function (ts) {
405  if (ts === undefined)
406  ts = Sanitizer.prefs.getIntPref("timeSpan");
407  if (ts === Sanitizer.TIMESPAN_EVERYTHING)
408  return null;
409 
410  // PRTime is microseconds while JS time is milliseconds
411  var endDate = Date.now() * 1000;
412  switch (ts) {
413  case Sanitizer.TIMESPAN_HOUR :
414  var startDate = endDate - 3600000000; // 1*60*60*1000000
415  break;
416  case Sanitizer.TIMESPAN_2HOURS :
417  startDate = endDate - 7200000000; // 2*60*60*1000000
418  break;
419  case Sanitizer.TIMESPAN_4HOURS :
420  startDate = endDate - 14400000000; // 4*60*60*1000000
421  break;
422  case Sanitizer.TIMESPAN_TODAY :
423  var d = new Date(); // Start with today
424  d.setHours(0); // zero us back to midnight...
425  d.setMinutes(0);
426  d.setSeconds(0);
427  startDate = d.valueOf() * 1000; // convert to epoch usec
428  break;
429  default:
430  throw "Invalid time span for clear private data: " + ts;
431  }
432  return [startDate, endDate];
433 };
434 
435 Sanitizer._prefs = null;
436 Sanitizer.__defineGetter__("prefs", function()
437 {
438  return Sanitizer._prefs ? Sanitizer._prefs
439  : Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
440  .getService(Components.interfaces.nsIPrefService)
441  .getBranch(Sanitizer.prefDomain);
442 });
443 
444 // Shows sanitization UI
445 Sanitizer.showUI = function(aParentWindow)
446 {
447  var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
448  .getService(Components.interfaces.nsIWindowWatcher);
449 #ifdef XP_MACOSX
450  ww.openWindow(null, // make this an app-modal window on Mac
451 #else
452  ww.openWindow(aParentWindow,
453 #endif
454  "chrome://browser/content/sanitize.xul",
455  "Sanitize",
456  "chrome,titlebar,dialog,centerscreen,modal",
457  null);
458 };
459 
464 Sanitizer.sanitize = function(aParentWindow)
465 {
466  Sanitizer.showUI(aParentWindow);
467 };
468 
469 Sanitizer.onStartup = function()
470 {
471  // we check for unclean exit with pending sanitization
472  Sanitizer._checkAndSanitize();
473 };
474 
475 Sanitizer.onShutdown = function()
476 {
477  // we check if sanitization is needed and perform it
478  Sanitizer._checkAndSanitize();
479 };
480 
481 // this is called on startup and shutdown, to perform pending sanitizations
482 Sanitizer._checkAndSanitize = function()
483 {
484  const prefs = Sanitizer.prefs;
485  if (prefs.getBoolPref(Sanitizer.prefShutdown) &&
486  !prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) {
487  // this is a shutdown or a startup after an unclean exit
488  var s = new Sanitizer();
489  s.prefDomain = "privacy.clearOnShutdown.";
490  s.sanitize() || // sanitize() returns null on full success
491  prefs.setBoolPref(Sanitizer.prefDidShutdown, true);
492  }
493 };
494 
495 
const Cc
var windows
var history
function clear(dbq)
getService(Ci.sbIFaceplateManager)
Sanitizer prefDomain
Definition: sanitize.js:388
function d(s)
Sanitizer sanitize
Definition: sanitize.js:464
var count
Definition: test_bug7406.js:32
return null
Definition: FeedWriter.js:1143
var os
const cacheService
Definition: pageInfo.js:195
var prefs
Definition: FeedWriter.js:1169
_setDateDatepicker endDate
const Ci
function Sanitizer()
Definition: sanitize.js:42
function range(x, y)
Definition: httpd.js:138