michael@0: // -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "LoadContextInfo", michael@0: "resource://gre/modules/LoadContextInfo.jsm"); michael@0: function Sanitizer() {} michael@0: michael@0: Sanitizer.prototype = { michael@0: // warning to the caller: this one may raise an exception (e.g. bug #265028) michael@0: clearItem: function (aItemName) michael@0: { michael@0: if (this.items[aItemName].canClear) michael@0: this.items[aItemName].clear(); michael@0: }, michael@0: michael@0: canClearItem: function (aItemName, aCallback, aArg) michael@0: { michael@0: let canClear = this.items[aItemName].canClear; michael@0: if (typeof canClear == "function"){ michael@0: canClear(aCallback, aArg); michael@0: } else { michael@0: aCallback(aItemName, canClear, aArg); michael@0: } michael@0: }, michael@0: michael@0: _prefDomain: "privacy.item.", michael@0: getNameFromPreference: function (aPreferenceName) michael@0: { michael@0: return aPreferenceName.substr(this._prefDomain.length); michael@0: }, michael@0: michael@0: /** michael@0: * Deletes privacy sensitive data in a batch, according to user preferences michael@0: * michael@0: * @returns null if everything's fine; an object in the form michael@0: * { itemName: error, ... } on (partial) failure michael@0: */ michael@0: sanitize: function () michael@0: { michael@0: var branch = Services.prefs.getBranch(this._prefDomain); michael@0: var errors = null; michael@0: for (var itemName in this.items) { michael@0: if ("clear" in item && branch.getBoolPref(itemName)) { michael@0: // Some of these clear() may raise exceptions (see bug #265028) michael@0: // to sanitize as much as possible, we catch and store them, michael@0: // rather than fail fast. michael@0: // Callers should check returned errors and give user feedback michael@0: // about items that could not be sanitized michael@0: let clearCallback = (itemName, aCanClear) => { michael@0: let item = this.items[itemName]; michael@0: try{ michael@0: if (aCanClear){ michael@0: item.clear(); michael@0: } michael@0: } catch(er){ michael@0: if (!errors){ michael@0: errors = {}; michael@0: } michael@0: errors[itemName] = er; michael@0: dump("Error sanitizing " + itemName + ":" + er + "\n"); michael@0: } michael@0: } michael@0: this.canClearItem(itemName, clearCallback); michael@0: } michael@0: } michael@0: return errors; michael@0: }, michael@0: michael@0: items: { michael@0: // Clear Sync account before passwords so that Sync still has access to the michael@0: // credentials to clean up device-specific records on the server. Also michael@0: // disable it before wiping history so we don't accidentally sync that. michael@0: syncAccount: { michael@0: clear: function () michael@0: { michael@0: Sync.disconnect(); michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED); michael@0: } michael@0: }, michael@0: michael@0: cache: { michael@0: clear: function () michael@0: { michael@0: var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); michael@0: try { michael@0: cache.clear(); michael@0: } catch(er) {} michael@0: michael@0: let imageCache = Cc["@mozilla.org/image/cache;1"].getService(Ci.imgICache); michael@0: try { michael@0: imageCache.clearCache(false); // true=chrome, false=content michael@0: } catch(er) {} michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return true; michael@0: } michael@0: }, michael@0: michael@0: cookies: { michael@0: clear: function () michael@0: { michael@0: var cookieMgr = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); michael@0: cookieMgr.removeAll(); michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return true; michael@0: } michael@0: }, michael@0: michael@0: siteSettings: { michael@0: clear: function () michael@0: { michael@0: // Clear site-specific permissions like "Allow this site to open popups" michael@0: Services.perms.removeAll(); michael@0: michael@0: // Clear site-specific settings like page-zoom level michael@0: var cps = Cc["@mozilla.org/content-pref/service;1"].getService(Ci.nsIContentPrefService2); michael@0: cps.removeAllDomains(null); michael@0: michael@0: // Clear "Never remember passwords for this site", which is not handled by michael@0: // the permission manager michael@0: var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); michael@0: var hosts = pwmgr.getAllDisabledHosts({}) michael@0: for each (var host in hosts) { michael@0: pwmgr.setLoginSavingEnabled(host, true); michael@0: } michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return true; michael@0: } michael@0: }, michael@0: michael@0: offlineApps: { michael@0: clear: function () michael@0: { michael@0: var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService); michael@0: var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null); michael@0: try { michael@0: appCacheStorage.asyncEvictStorage(null); michael@0: } catch(er) {} michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return true; michael@0: } michael@0: }, michael@0: michael@0: history: { michael@0: clear: function () michael@0: { michael@0: try { michael@0: Services.obs.notifyObservers(null, "browser:purge-session-history", ""); michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError("Failed to notify observers of " michael@0: + "browser:purge-session-history: " michael@0: + e); michael@0: } michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: // bug 347231: Always allow clearing history due to dependencies on michael@0: // the browser:purge-session-history notification. (like error console) michael@0: return true; michael@0: } michael@0: }, michael@0: michael@0: formdata: { michael@0: clear: function () michael@0: { michael@0: //Clear undo history of all searchBars michael@0: var windows = Services.wm.getEnumerator("navigator:browser"); michael@0: while (windows.hasMoreElements()) { michael@0: var searchBar = windows.getNext().document.getElementById("searchbar"); michael@0: if (searchBar) { michael@0: searchBar.value = ""; michael@0: searchBar.textbox.editor.transactionManager.clear(); michael@0: } michael@0: } michael@0: FormHistory.update({op : "remove"}); michael@0: }, michael@0: michael@0: canClear : function(aCallback, aArg) michael@0: { michael@0: let count = 0; michael@0: let countDone = { michael@0: handleResult : function(aResult) { count = aResult; }, michael@0: handleError : function(aError) { Components.utils.reportError(aError); }, michael@0: handleCompletion : function(aReason) { aCallback("formdata", aReason == 0 && count > 0, aArg); } michael@0: }; michael@0: FormHistory.count({}, countDone); michael@0: } michael@0: }, michael@0: michael@0: downloads: { michael@0: clear: function () michael@0: { michael@0: var dlMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); michael@0: dlMgr.cleanUp(); michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: var dlMgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager); michael@0: return dlMgr.canCleanUp; michael@0: } michael@0: }, michael@0: michael@0: passwords: { michael@0: clear: function () michael@0: { michael@0: var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); michael@0: pwmgr.removeAllLogins(); michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); michael@0: var count = pwmgr.countLogins("", "", ""); // count all logins michael@0: return (count > 0); michael@0: } michael@0: }, michael@0: michael@0: sessions: { michael@0: clear: function () michael@0: { michael@0: // clear all auth tokens michael@0: var sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing); michael@0: sdr.logoutAndTeardown(); michael@0: michael@0: // clear plain HTTP auth sessions michael@0: var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].getService(Ci.nsIHttpAuthManager); michael@0: authMgr.clearAll(); michael@0: }, michael@0: michael@0: get canClear() michael@0: { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: michael@0: // "Static" members michael@0: Sanitizer.prefDomain = "privacy.sanitize."; michael@0: Sanitizer.prefShutdown = "sanitizeOnShutdown"; michael@0: Sanitizer.prefDidShutdown = "didShutdownSanitize"; michael@0: michael@0: Sanitizer._prefs = null; michael@0: Sanitizer.__defineGetter__("prefs", function() michael@0: { michael@0: return Sanitizer._prefs ? Sanitizer._prefs michael@0: : Sanitizer._prefs = Cc["@mozilla.org/preferences-service;1"] michael@0: .getService(Ci.nsIPrefService) michael@0: .getBranch(Sanitizer.prefDomain); michael@0: }); michael@0: michael@0: /** michael@0: * Deletes privacy sensitive data in a batch, optionally showing the michael@0: * sanitize UI, according to user preferences michael@0: * michael@0: * @returns null if everything's fine michael@0: * an object in the form { itemName: error, ... } on (partial) failure michael@0: */ michael@0: Sanitizer.sanitize = function() michael@0: { michael@0: return new Sanitizer().sanitize(); michael@0: }; michael@0: michael@0: Sanitizer.onStartup = function() michael@0: { michael@0: // we check for unclean exit with pending sanitization michael@0: Sanitizer._checkAndSanitize(); michael@0: }; michael@0: michael@0: Sanitizer.onShutdown = function() michael@0: { michael@0: // we check if sanitization is needed and perform it michael@0: Sanitizer._checkAndSanitize(); michael@0: }; michael@0: michael@0: // this is called on startup and shutdown, to perform pending sanitizations michael@0: Sanitizer._checkAndSanitize = function() michael@0: { michael@0: const prefs = Sanitizer.prefs; michael@0: if (prefs.getBoolPref(Sanitizer.prefShutdown) && michael@0: !prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) { michael@0: // this is a shutdown or a startup after an unclean exit michael@0: Sanitizer.sanitize() || // sanitize() returns null on full success michael@0: prefs.setBoolPref(Sanitizer.prefDidShutdown, true); michael@0: } michael@0: }; michael@0: michael@0: