Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | Components.utils.import("resource://gre/modules/Services.jsm"); |
michael@0 | 6 | Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 7 | Components.utils.import("resource://gre/modules/NetUtil.jsm"); |
michael@0 | 8 | Components.utils.import("resource://gre/modules/Task.jsm"); |
michael@0 | 9 | XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", |
michael@0 | 10 | "resource://gre/modules/PlacesUtils.jsm"); |
michael@0 | 11 | XPCOMUtils.defineLazyModuleGetter(this, "Downloads", |
michael@0 | 12 | "resource://gre/modules/Downloads.jsm"); |
michael@0 | 13 | |
michael@0 | 14 | this.EXPORTED_SYMBOLS = ["ForgetAboutSite"]; |
michael@0 | 15 | |
michael@0 | 16 | /** |
michael@0 | 17 | * Returns true if the string passed in is part of the root domain of the |
michael@0 | 18 | * current string. For example, if this is "www.mozilla.org", and we pass in |
michael@0 | 19 | * "mozilla.org", this will return true. It would return false the other way |
michael@0 | 20 | * around. |
michael@0 | 21 | */ |
michael@0 | 22 | function hasRootDomain(str, aDomain) |
michael@0 | 23 | { |
michael@0 | 24 | let index = str.indexOf(aDomain); |
michael@0 | 25 | // If aDomain is not found, we know we do not have it as a root domain. |
michael@0 | 26 | if (index == -1) |
michael@0 | 27 | return false; |
michael@0 | 28 | |
michael@0 | 29 | // If the strings are the same, we obviously have a match. |
michael@0 | 30 | if (str == aDomain) |
michael@0 | 31 | return true; |
michael@0 | 32 | |
michael@0 | 33 | // Otherwise, we have aDomain as our root domain iff the index of aDomain is |
michael@0 | 34 | // aDomain.length subtracted from our length and (since we do not have an |
michael@0 | 35 | // exact match) the character before the index is a dot or slash. |
michael@0 | 36 | let prevChar = str[index - 1]; |
michael@0 | 37 | return (index == (str.length - aDomain.length)) && |
michael@0 | 38 | (prevChar == "." || prevChar == "/"); |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | const Cc = Components.classes; |
michael@0 | 42 | const Ci = Components.interfaces; |
michael@0 | 43 | const Cu = Components.utils; |
michael@0 | 44 | |
michael@0 | 45 | this.ForgetAboutSite = { |
michael@0 | 46 | removeDataFromDomain: function CRH_removeDataFromDomain(aDomain) |
michael@0 | 47 | { |
michael@0 | 48 | PlacesUtils.history.removePagesFromHost(aDomain, true); |
michael@0 | 49 | |
michael@0 | 50 | // Cache |
michael@0 | 51 | let (cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"]. |
michael@0 | 52 | getService(Ci.nsICacheStorageService)) { |
michael@0 | 53 | // NOTE: there is no way to clear just that domain, so we clear out |
michael@0 | 54 | // everything) |
michael@0 | 55 | try { |
michael@0 | 56 | cs.clear(); |
michael@0 | 57 | } catch (ex) { |
michael@0 | 58 | Cu.reportError("Exception thrown while clearing the cache: " + |
michael@0 | 59 | ex.toString()); |
michael@0 | 60 | } |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | // Image Cache |
michael@0 | 64 | let (imageCache = Cc["@mozilla.org/image/tools;1"]. |
michael@0 | 65 | getService(Ci.imgITools).getImgCacheForDocument(null)) { |
michael@0 | 66 | try { |
michael@0 | 67 | imageCache.clearCache(false); // true=chrome, false=content |
michael@0 | 68 | } catch (ex) { |
michael@0 | 69 | Cu.reportError("Exception thrown while clearing the image cache: " + |
michael@0 | 70 | ex.toString()); |
michael@0 | 71 | } |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | // Cookies |
michael@0 | 75 | let (cm = Cc["@mozilla.org/cookiemanager;1"]. |
michael@0 | 76 | getService(Ci.nsICookieManager2)) { |
michael@0 | 77 | let enumerator = cm.getCookiesFromHost(aDomain); |
michael@0 | 78 | while (enumerator.hasMoreElements()) { |
michael@0 | 79 | let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); |
michael@0 | 80 | cm.remove(cookie.host, cookie.name, cookie.path, false); |
michael@0 | 81 | } |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | // Plugin data |
michael@0 | 85 | const phInterface = Ci.nsIPluginHost; |
michael@0 | 86 | const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; |
michael@0 | 87 | let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) { |
michael@0 | 88 | let tags = ph.getPluginTags(); |
michael@0 | 89 | for (let i = 0; i < tags.length; i++) { |
michael@0 | 90 | try { |
michael@0 | 91 | ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1); |
michael@0 | 92 | } catch (e) { |
michael@0 | 93 | // Ignore errors from the plugin |
michael@0 | 94 | } |
michael@0 | 95 | } |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | // Downloads |
michael@0 | 99 | let useJSTransfer = false; |
michael@0 | 100 | try { |
michael@0 | 101 | // This method throws an exception if the old Download Manager is disabled. |
michael@0 | 102 | Services.downloads.activeDownloadCount; |
michael@0 | 103 | } catch (ex) { |
michael@0 | 104 | useJSTransfer = true; |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | if (useJSTransfer) { |
michael@0 | 108 | Task.spawn(function() { |
michael@0 | 109 | let list = yield Downloads.getList(Downloads.ALL); |
michael@0 | 110 | list.removeFinished(download => hasRootDomain( |
michael@0 | 111 | NetUtil.newURI(download.source.url).host, aDomain)); |
michael@0 | 112 | }).then(null, Cu.reportError); |
michael@0 | 113 | } |
michael@0 | 114 | else { |
michael@0 | 115 | let (dm = Cc["@mozilla.org/download-manager;1"]. |
michael@0 | 116 | getService(Ci.nsIDownloadManager)) { |
michael@0 | 117 | // Active downloads |
michael@0 | 118 | for (let enumerator of [dm.activeDownloads, dm.activePrivateDownloads]) { |
michael@0 | 119 | while (enumerator.hasMoreElements()) { |
michael@0 | 120 | let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload); |
michael@0 | 121 | if (hasRootDomain(dl.source.host, aDomain)) { |
michael@0 | 122 | dl.cancel(); |
michael@0 | 123 | dl.remove(); |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | function deleteAllLike(db) { |
michael@0 | 129 | // NOTE: This is lossy, but we feel that it is OK to be lossy here and not |
michael@0 | 130 | // invoke the cost of creating a URI for each download entry and |
michael@0 | 131 | // ensure that the hostname matches. |
michael@0 | 132 | let stmt = db.createStatement( |
michael@0 | 133 | "DELETE FROM moz_downloads " + |
michael@0 | 134 | "WHERE source LIKE ?1 ESCAPE '/' " + |
michael@0 | 135 | "AND state NOT IN (?2, ?3, ?4)" |
michael@0 | 136 | ); |
michael@0 | 137 | let pattern = stmt.escapeStringForLIKE(aDomain, "/"); |
michael@0 | 138 | stmt.bindByIndex(0, "%" + pattern + "%"); |
michael@0 | 139 | stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING); |
michael@0 | 140 | stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED); |
michael@0 | 141 | stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED); |
michael@0 | 142 | try { |
michael@0 | 143 | stmt.execute(); |
michael@0 | 144 | } |
michael@0 | 145 | finally { |
michael@0 | 146 | stmt.finalize(); |
michael@0 | 147 | } |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | // Completed downloads |
michael@0 | 151 | deleteAllLike(dm.DBConnection); |
michael@0 | 152 | deleteAllLike(dm.privateDBConnection); |
michael@0 | 153 | |
michael@0 | 154 | // We want to rebuild the list if the UI is showing, so dispatch the |
michael@0 | 155 | // observer topic |
michael@0 | 156 | let os = Cc["@mozilla.org/observer-service;1"]. |
michael@0 | 157 | getService(Ci.nsIObserverService); |
michael@0 | 158 | os.notifyObservers(null, "download-manager-remove-download", null); |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | // Passwords |
michael@0 | 163 | let (lm = Cc["@mozilla.org/login-manager;1"]. |
michael@0 | 164 | getService(Ci.nsILoginManager)) { |
michael@0 | 165 | // Clear all passwords for domain |
michael@0 | 166 | try { |
michael@0 | 167 | let logins = lm.getAllLogins(); |
michael@0 | 168 | for (let i = 0; i < logins.length; i++) |
michael@0 | 169 | if (hasRootDomain(logins[i].hostname, aDomain)) |
michael@0 | 170 | lm.removeLogin(logins[i]); |
michael@0 | 171 | } |
michael@0 | 172 | // XXXehsan: is there a better way to do this rather than this |
michael@0 | 173 | // hacky comparison? |
michael@0 | 174 | catch (ex if ex.message.indexOf("User canceled Master Password entry") != -1) { } |
michael@0 | 175 | |
michael@0 | 176 | // Clear any "do not save for this site" for this domain |
michael@0 | 177 | let disabledHosts = lm.getAllDisabledHosts(); |
michael@0 | 178 | for (let i = 0; i < disabledHosts.length; i++) |
michael@0 | 179 | if (hasRootDomain(disabledHosts[i], aDomain)) |
michael@0 | 180 | lm.setLoginSavingEnabled(disabledHosts, true); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | // Permissions |
michael@0 | 184 | let (pm = Cc["@mozilla.org/permissionmanager;1"]. |
michael@0 | 185 | getService(Ci.nsIPermissionManager)) { |
michael@0 | 186 | // Enumerate all of the permissions, and if one matches, remove it |
michael@0 | 187 | let enumerator = pm.enumerator; |
michael@0 | 188 | while (enumerator.hasMoreElements()) { |
michael@0 | 189 | let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission); |
michael@0 | 190 | if (hasRootDomain(perm.host, aDomain)) |
michael@0 | 191 | pm.remove(perm.host, perm.type); |
michael@0 | 192 | } |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | // Offline Storages |
michael@0 | 196 | let (qm = Cc["@mozilla.org/dom/quota/manager;1"]. |
michael@0 | 197 | getService(Ci.nsIQuotaManager)) { |
michael@0 | 198 | // delete data from both HTTP and HTTPS sites |
michael@0 | 199 | let caUtils = {}; |
michael@0 | 200 | let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. |
michael@0 | 201 | getService(Ci.mozIJSSubScriptLoader); |
michael@0 | 202 | scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js", |
michael@0 | 203 | caUtils); |
michael@0 | 204 | let httpURI = caUtils.makeURI("http://" + aDomain); |
michael@0 | 205 | let httpsURI = caUtils.makeURI("https://" + aDomain); |
michael@0 | 206 | qm.clearStoragesForURI(httpURI); |
michael@0 | 207 | qm.clearStoragesForURI(httpsURI); |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | function onContentPrefsRemovalFinished() { |
michael@0 | 211 | // Everybody else (including extensions) |
michael@0 | 212 | Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | // Content Preferences |
michael@0 | 216 | let cps2 = Cc["@mozilla.org/content-pref/service;1"]. |
michael@0 | 217 | getService(Ci.nsIContentPrefService2); |
michael@0 | 218 | cps2.removeBySubdomain(aDomain, null, { |
michael@0 | 219 | handleCompletion: function() onContentPrefsRemovalFinished(), |
michael@0 | 220 | handleError: function() {} |
michael@0 | 221 | }); |
michael@0 | 222 | |
michael@0 | 223 | // Predictive network data - like cache, no way to clear this per |
michael@0 | 224 | // domain, so just trash it all |
michael@0 | 225 | let ns = Cc["@mozilla.org/network/seer;1"]. |
michael@0 | 226 | getService(Ci.nsINetworkSeer); |
michael@0 | 227 | ns.reset(); |
michael@0 | 228 | } |
michael@0 | 229 | }; |