зеркало из https://github.com/mozilla/gecko-dev.git
232 строки
8.1 KiB
JavaScript
232 строки
8.1 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
|
|
this.EXPORTED_SYMBOLS = ["ForgetAboutSite"];
|
|
|
|
/**
|
|
* Returns true if the string passed in is part of the root domain of the
|
|
* current string. For example, if this is "www.mozilla.org", and we pass in
|
|
* "mozilla.org", this will return true. It would return false the other way
|
|
* around.
|
|
*/
|
|
function hasRootDomain(str, aDomain)
|
|
{
|
|
let index = str.indexOf(aDomain);
|
|
// If aDomain is not found, we know we do not have it as a root domain.
|
|
if (index == -1)
|
|
return false;
|
|
|
|
// If the strings are the same, we obviously have a match.
|
|
if (str == aDomain)
|
|
return true;
|
|
|
|
// Otherwise, we have aDomain as our root domain iff the index of aDomain is
|
|
// aDomain.length subtracted from our length and (since we do not have an
|
|
// exact match) the character before the index is a dot or slash.
|
|
let prevChar = str[index - 1];
|
|
return (index == (str.length - aDomain.length)) &&
|
|
(prevChar == "." || prevChar == "/");
|
|
}
|
|
|
|
const Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const Cu = Components.utils;
|
|
|
|
this.ForgetAboutSite = {
|
|
removeDataFromDomain: function CRH_removeDataFromDomain(aDomain)
|
|
{
|
|
// clear any and all network geolocation provider sessions
|
|
try {
|
|
Services.prefs.deleteBranch("geo.wifi.access_token.");
|
|
} catch (e) {}
|
|
|
|
// History
|
|
let (bh = Cc["@mozilla.org/browser/global-history;2"].
|
|
getService(Ci.nsIBrowserHistory)) {
|
|
bh.removePagesFromHost(aDomain, true);
|
|
}
|
|
|
|
// Cache
|
|
let (cs = Cc["@mozilla.org/network/cache-service;1"].
|
|
getService(Ci.nsICacheService)) {
|
|
// NOTE: there is no way to clear just that domain, so we clear out
|
|
// everything)
|
|
try {
|
|
cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
|
} catch (ex) {
|
|
Cu.reportError("Exception thrown while clearing the cache: " +
|
|
ex.toString());
|
|
}
|
|
}
|
|
|
|
// Image Cache
|
|
let (imageCache = Cc["@mozilla.org/image/tools;1"].
|
|
getService(Ci.imgITools).getImgCacheForDocument(null)) {
|
|
try {
|
|
imageCache.clearCache(false); // true=chrome, false=content
|
|
} catch (ex) {
|
|
Cu.reportError("Exception thrown while clearing the image cache: " +
|
|
ex.toString());
|
|
}
|
|
}
|
|
|
|
// Cookies
|
|
let (cm = Cc["@mozilla.org/cookiemanager;1"].
|
|
getService(Ci.nsICookieManager2)) {
|
|
let enumerator = cm.getCookiesFromHost(aDomain);
|
|
while (enumerator.hasMoreElements()) {
|
|
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
|
|
cm.remove(cookie.host, cookie.name, cookie.path, false);
|
|
}
|
|
}
|
|
|
|
// Plugin data
|
|
const phInterface = Ci.nsIPluginHost;
|
|
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
|
let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) {
|
|
let tags = ph.getPluginTags();
|
|
for (let i = 0; i < tags.length; i++) {
|
|
try {
|
|
ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1);
|
|
} catch (e) {
|
|
// Ignore errors from the plugin
|
|
}
|
|
}
|
|
}
|
|
|
|
// Downloads
|
|
let (dm = Cc["@mozilla.org/download-manager;1"].
|
|
getService(Ci.nsIDownloadManager)) {
|
|
// Active downloads
|
|
for (let enumerator of [dm.activeDownloads, dm.activePrivateDownloads]) {
|
|
while (enumerator.hasMoreElements()) {
|
|
let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
|
|
if (hasRootDomain(dl.source.host, aDomain)) {
|
|
dl.cancel();
|
|
dl.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
function deleteAllLike(db) {
|
|
// NOTE: This is lossy, but we feel that it is OK to be lossy here and not
|
|
// invoke the cost of creating a URI for each download entry and
|
|
// ensure that the hostname matches.
|
|
let stmt = db.createStatement(
|
|
"DELETE FROM moz_downloads " +
|
|
"WHERE source LIKE ?1 ESCAPE '/' " +
|
|
"AND state NOT IN (?2, ?3, ?4)"
|
|
);
|
|
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
|
|
stmt.bindByIndex(0, "%" + pattern + "%");
|
|
stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
|
|
stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
|
|
stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
|
|
try {
|
|
stmt.execute();
|
|
}
|
|
finally {
|
|
stmt.finalize();
|
|
}
|
|
}
|
|
|
|
// Completed downloads
|
|
deleteAllLike(dm.DBConnection);
|
|
deleteAllLike(dm.privateDBConnection);
|
|
|
|
// We want to rebuild the list if the UI is showing, so dispatch the
|
|
// observer topic
|
|
let os = Cc["@mozilla.org/observer-service;1"].
|
|
getService(Ci.nsIObserverService);
|
|
os.notifyObservers(null, "download-manager-remove-download", null);
|
|
}
|
|
|
|
// Passwords
|
|
let (lm = Cc["@mozilla.org/login-manager;1"].
|
|
getService(Ci.nsILoginManager)) {
|
|
// Clear all passwords for domain
|
|
try {
|
|
let logins = lm.getAllLogins();
|
|
for (let i = 0; i < logins.length; i++)
|
|
if (hasRootDomain(logins[i].hostname, aDomain))
|
|
lm.removeLogin(logins[i]);
|
|
}
|
|
// XXXehsan: is there a better way to do this rather than this
|
|
// hacky comparison?
|
|
catch (ex if ex.message.indexOf("User canceled Master Password entry") != -1) { }
|
|
|
|
// Clear any "do not save for this site" for this domain
|
|
let disabledHosts = lm.getAllDisabledHosts();
|
|
for (let i = 0; i < disabledHosts.length; i++)
|
|
if (hasRootDomain(disabledHosts[i], aDomain))
|
|
lm.setLoginSavingEnabled(disabledHosts, true);
|
|
}
|
|
|
|
// Permissions
|
|
let (pm = Cc["@mozilla.org/permissionmanager;1"].
|
|
getService(Ci.nsIPermissionManager)) {
|
|
// Enumerate all of the permissions, and if one matches, remove it
|
|
let enumerator = pm.enumerator;
|
|
while (enumerator.hasMoreElements()) {
|
|
let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
|
|
if (hasRootDomain(perm.host, aDomain))
|
|
pm.remove(perm.host, perm.type);
|
|
}
|
|
}
|
|
|
|
// Content Preferences
|
|
let (cp = Cc["@mozilla.org/content-pref/service;1"].
|
|
getService(Ci.nsIContentPrefService)) {
|
|
let db = cp.DBConnection;
|
|
// First we need to get the list of "groups" which are really just domains
|
|
let names = [];
|
|
let stmt = db.createStatement(
|
|
"SELECT name " +
|
|
"FROM groups " +
|
|
"WHERE name LIKE ?1 ESCAPE '/'"
|
|
);
|
|
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
|
|
stmt.bindByIndex(0, "%" + pattern);
|
|
try {
|
|
while (stmt.executeStep())
|
|
if (hasRootDomain(stmt.getString(0), aDomain))
|
|
names.push(stmt.getString(0));
|
|
}
|
|
finally {
|
|
stmt.finalize();
|
|
}
|
|
|
|
// Now, for each name we got back, remove all of its prefs.
|
|
for (let i = 0; i < names.length; i++) {
|
|
let uri = names[i];
|
|
let enumerator = cp.getPrefs(uri, null).enumerator;
|
|
while (enumerator.hasMoreElements()) {
|
|
let pref = enumerator.getNext().QueryInterface(Ci.nsIProperty);
|
|
cp.removePref(uri, pref.name, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Indexed DB
|
|
let (idbm = Cc["@mozilla.org/dom/indexeddb/manager;1"].
|
|
getService(Ci.nsIIndexedDatabaseManager)) {
|
|
// delete data from both HTTP and HTTPS sites
|
|
let caUtils = {};
|
|
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
|
getService(Ci.mozIJSSubScriptLoader);
|
|
scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js",
|
|
caUtils);
|
|
let httpURI = caUtils.makeURI("http://" + aDomain);
|
|
let httpsURI = caUtils.makeURI("https://" + aDomain);
|
|
idbm.clearDatabasesForURI(httpURI);
|
|
idbm.clearDatabasesForURI(httpsURI);
|
|
}
|
|
|
|
// Everybody else (including extensions)
|
|
Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain);
|
|
}
|
|
};
|