mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
4d6a633bba
The -*- file variable lines -*- establish per-file settings that Emacs will pick up. This patch makes the following changes to those lines (and touches nothing else): - Never set the buffer's mode. Years ago, Emacs did not have a good JavaScript mode, so it made sense to use Java or C++ mode in .js files. However, Emacs has had js-mode for years now; it's perfectly serviceable, and is available and enabled by default in all major Emacs packagings. Selecting a mode in the -*- file variable line -*- is almost always the wrong thing to do anyway. It overrides Emacs's default choice, which is (now) reasonable; and even worse, it overrides settings the user might have made in their '.emacs' file for that file extension. It's only useful when there's something specific about that particular file that makes a particular mode appropriate. - Correctly propagate settings that establish the correct indentation level for this file: c-basic-offset and js2-basic-offset should be js-indent-level. Whatever value they're given should be preserved; different parts of our tree use different indentation styles. - We don't use tabs in Mozilla JS code. Always set indent-tabs-mode: nil. Remove tab-width: settings, at least in files that don't contain tab characters. - Remove js2-mode settings that belong in the user's .emacs file, like js2-skip-preprocessor-directives.
513 lines
17 KiB
JavaScript
513 lines
17 KiB
JavaScript
# -*- indent-tabs-mode: nil; js-indent-level: 4 -*-
|
|
# 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/XPCOMUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
|
"resource://gre/modules/PlacesUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
|
"resource://gre/modules/FormHistory.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
|
"resource://gre/modules/Downloads.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
|
"resource://gre/modules/Promise.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|
"resource://gre/modules/Task.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
|
"resource:///modules/DownloadsCommon.jsm");
|
|
|
|
function Sanitizer() {}
|
|
Sanitizer.prototype = {
|
|
// warning to the caller: this one may raise an exception (e.g. bug #265028)
|
|
clearItem: function (aItemName)
|
|
{
|
|
if (this.items[aItemName].canClear)
|
|
this.items[aItemName].clear();
|
|
},
|
|
|
|
canClearItem: function (aItemName, aCallback, aArg)
|
|
{
|
|
let canClear = this.items[aItemName].canClear;
|
|
if (typeof canClear == "function") {
|
|
canClear(aCallback, aArg);
|
|
return false;
|
|
}
|
|
|
|
aCallback(aItemName, canClear, aArg);
|
|
return canClear;
|
|
},
|
|
|
|
prefDomain: "",
|
|
|
|
getNameFromPreference: function (aPreferenceName)
|
|
{
|
|
return aPreferenceName.substr(this.prefDomain.length);
|
|
},
|
|
|
|
/**
|
|
* Deletes privacy sensitive data in a batch, according to user preferences.
|
|
* Returns a promise which is resolved if no errors occurred. If an error
|
|
* occurs, a message is reported to the console and all other items are still
|
|
* cleared before the promise is finally rejected.
|
|
*/
|
|
sanitize: function ()
|
|
{
|
|
var deferred = Promise.defer();
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
.getService(Components.interfaces.nsIPrefService);
|
|
var branch = psvc.getBranch(this.prefDomain);
|
|
var seenError = false;
|
|
|
|
// Cache the range of times to clear
|
|
if (this.ignoreTimespan)
|
|
var range = null; // If we ignore timespan, clear everything
|
|
else
|
|
range = this.range || Sanitizer.getClearRange();
|
|
|
|
let itemCount = Object.keys(this.items).length;
|
|
let onItemComplete = function() {
|
|
if (!--itemCount) {
|
|
seenError ? deferred.reject() : deferred.resolve();
|
|
}
|
|
};
|
|
for (var itemName in this.items) {
|
|
let item = this.items[itemName];
|
|
item.range = range;
|
|
if ("clear" in item && branch.getBoolPref(itemName)) {
|
|
let clearCallback = (itemName, aCanClear) => {
|
|
// Some of these clear() may raise exceptions (see bug #265028)
|
|
// to sanitize as much as possible, we catch and store them,
|
|
// rather than fail fast.
|
|
// Callers should check returned errors and give user feedback
|
|
// about items that could not be sanitized
|
|
let item = this.items[itemName];
|
|
try {
|
|
if (aCanClear)
|
|
item.clear();
|
|
} catch(er) {
|
|
seenError = true;
|
|
Components.utils.reportError("Error sanitizing " + itemName +
|
|
": " + er + "\n");
|
|
}
|
|
onItemComplete();
|
|
};
|
|
this.canClearItem(itemName, clearCallback);
|
|
} else {
|
|
onItemComplete();
|
|
}
|
|
}
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
// Time span only makes sense in certain cases. Consumers who want
|
|
// to only clear some private data can opt in by setting this to false,
|
|
// and can optionally specify a specific range. If timespan is not ignored,
|
|
// and range is not set, sanitize() will use the value of the timespan
|
|
// pref to determine a range
|
|
ignoreTimespan : true,
|
|
range : null,
|
|
|
|
items: {
|
|
cache: {
|
|
clear: function ()
|
|
{
|
|
var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].
|
|
getService(Ci.nsICacheStorageService);
|
|
try {
|
|
// Cache doesn't consult timespan, nor does it have the
|
|
// facility for timespan-based eviction. Wipe it.
|
|
cache.clear();
|
|
} catch(er) {}
|
|
|
|
var imageCache = Cc["@mozilla.org/image/tools;1"].
|
|
getService(Ci.imgITools).getImgCacheForDocument(null);
|
|
try {
|
|
imageCache.clearCache(false); // true=chrome, false=content
|
|
} catch(er) {}
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
return true;
|
|
}
|
|
},
|
|
|
|
cookies: {
|
|
clear: function ()
|
|
{
|
|
var cookieMgr = Components.classes["@mozilla.org/cookiemanager;1"]
|
|
.getService(Ci.nsICookieManager);
|
|
if (this.range) {
|
|
// Iterate through the cookies and delete any created after our cutoff.
|
|
var cookiesEnum = cookieMgr.enumerator;
|
|
while (cookiesEnum.hasMoreElements()) {
|
|
var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
|
|
|
|
if (cookie.creationTime > this.range[0])
|
|
// This cookie was created after our cutoff, clear it
|
|
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
|
|
}
|
|
}
|
|
else {
|
|
// Remove everything
|
|
cookieMgr.removeAll();
|
|
}
|
|
|
|
// Clear plugin data.
|
|
const phInterface = Ci.nsIPluginHost;
|
|
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
|
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
|
|
|
|
// Determine age range in seconds. (-1 means clear all.) We don't know
|
|
// that this.range[1] is actually now, so we compute age range based
|
|
// on the lower bound. If this.range results in a negative age, do
|
|
// nothing.
|
|
let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000)
|
|
: -1;
|
|
if (!this.range || age >= 0) {
|
|
let tags = ph.getPluginTags();
|
|
for (let i = 0; i < tags.length; i++) {
|
|
try {
|
|
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, age);
|
|
} catch (e) {
|
|
// If the plugin doesn't support clearing by age, clear everything.
|
|
if (e.result == Components.results.
|
|
NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
|
|
try {
|
|
ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, -1);
|
|
} catch (e) {
|
|
// Ignore errors from the plugin
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
return true;
|
|
}
|
|
},
|
|
|
|
offlineApps: {
|
|
clear: function ()
|
|
{
|
|
Components.utils.import("resource:///modules/offlineAppCache.jsm");
|
|
OfflineAppCacheHelper.clear();
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
return true;
|
|
}
|
|
},
|
|
|
|
history: {
|
|
clear: function ()
|
|
{
|
|
if (this.range)
|
|
PlacesUtils.history.removeVisitsByTimeframe(this.range[0], this.range[1]);
|
|
else
|
|
PlacesUtils.history.removeAllPages();
|
|
|
|
try {
|
|
var os = Components.classes["@mozilla.org/observer-service;1"]
|
|
.getService(Components.interfaces.nsIObserverService);
|
|
os.notifyObservers(null, "browser:purge-session-history", "");
|
|
}
|
|
catch (e) { }
|
|
|
|
try {
|
|
var predictor = Components.classes["@mozilla.org/network/predictor;1"]
|
|
.getService(Components.interfaces.nsINetworkPredictor);
|
|
predictor.reset();
|
|
} catch (e) { }
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
// bug 347231: Always allow clearing history due to dependencies on
|
|
// the browser:purge-session-history notification. (like error console)
|
|
return true;
|
|
}
|
|
},
|
|
|
|
formdata: {
|
|
clear: function ()
|
|
{
|
|
// Clear undo history of all searchBars
|
|
var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
|
|
.getService(Components.interfaces.nsIWindowMediator);
|
|
var windows = windowManager.getEnumerator("navigator:browser");
|
|
while (windows.hasMoreElements()) {
|
|
let currentWindow = windows.getNext();
|
|
let currentDocument = currentWindow.document;
|
|
let searchBar = currentDocument.getElementById("searchbar");
|
|
if (searchBar)
|
|
searchBar.textbox.reset();
|
|
let tabBrowser = currentWindow.gBrowser;
|
|
for (let tab of tabBrowser.tabs) {
|
|
if (tabBrowser.isFindBarInitialized(tab))
|
|
tabBrowser.getFindBar(tab).clear();
|
|
}
|
|
// Clear any saved find value
|
|
tabBrowser._lastFindValue = "";
|
|
}
|
|
|
|
let change = { op: "remove" };
|
|
if (this.range) {
|
|
[ change.firstUsedStart, change.firstUsedEnd ] = this.range;
|
|
}
|
|
FormHistory.update(change);
|
|
},
|
|
|
|
canClear : function(aCallback, aArg)
|
|
{
|
|
var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
|
|
.getService(Components.interfaces.nsIWindowMediator);
|
|
var windows = windowManager.getEnumerator("navigator:browser");
|
|
while (windows.hasMoreElements()) {
|
|
let currentWindow = windows.getNext();
|
|
let currentDocument = currentWindow.document;
|
|
let searchBar = currentDocument.getElementById("searchbar");
|
|
if (searchBar) {
|
|
let transactionMgr = searchBar.textbox.editor.transactionManager;
|
|
if (searchBar.value ||
|
|
transactionMgr.numberOfUndoItems ||
|
|
transactionMgr.numberOfRedoItems) {
|
|
aCallback("formdata", true, aArg);
|
|
return false;
|
|
}
|
|
}
|
|
let tabBrowser = currentWindow.gBrowser;
|
|
let findBarCanClear = Array.some(tabBrowser.tabs, function (aTab) {
|
|
return tabBrowser.isFindBarInitialized(aTab) &&
|
|
tabBrowser.getFindBar(aTab).canClear;
|
|
});
|
|
if (findBarCanClear) {
|
|
aCallback("formdata", true, aArg);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
let count = 0;
|
|
let countDone = {
|
|
handleResult : function(aResult) count = aResult,
|
|
handleError : function(aError) Components.utils.reportError(aError),
|
|
handleCompletion :
|
|
function(aReason) { aCallback("formdata", aReason == 0 && count > 0, aArg); }
|
|
};
|
|
FormHistory.count({}, countDone);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
downloads: {
|
|
clear: function ()
|
|
{
|
|
Task.spawn(function () {
|
|
let filterByTime = null;
|
|
if (this.range) {
|
|
// Convert microseconds back to milliseconds for date comparisons.
|
|
let rangeBeginMs = this.range[0] / 1000;
|
|
let rangeEndMs = this.range[1] / 1000;
|
|
filterByTime = download => download.startTime >= rangeBeginMs &&
|
|
download.startTime <= rangeEndMs;
|
|
}
|
|
|
|
// Clear all completed/cancelled downloads
|
|
let list = yield Downloads.getList(Downloads.ALL);
|
|
list.removeFinished(filterByTime);
|
|
}.bind(this)).then(null, Components.utils.reportError);
|
|
},
|
|
|
|
canClear : function(aCallback, aArg)
|
|
{
|
|
aCallback("downloads", true, aArg);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
passwords: {
|
|
clear: function ()
|
|
{
|
|
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
|
.getService(Components.interfaces.nsILoginManager);
|
|
// Passwords are timeless, and don't respect the timeSpan setting
|
|
pwmgr.removeAllLogins();
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
|
.getService(Components.interfaces.nsILoginManager);
|
|
var count = pwmgr.countLogins("", "", ""); // count all logins
|
|
return (count > 0);
|
|
}
|
|
},
|
|
|
|
sessions: {
|
|
clear: function ()
|
|
{
|
|
// clear all auth tokens
|
|
var sdr = Components.classes["@mozilla.org/security/sdr;1"]
|
|
.getService(Components.interfaces.nsISecretDecoderRing);
|
|
sdr.logoutAndTeardown();
|
|
|
|
// clear FTP and plain HTTP auth sessions
|
|
var os = Components.classes["@mozilla.org/observer-service;1"]
|
|
.getService(Components.interfaces.nsIObserverService);
|
|
os.notifyObservers(null, "net:clear-active-logins", null);
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
return true;
|
|
}
|
|
},
|
|
|
|
siteSettings: {
|
|
clear: function ()
|
|
{
|
|
// Clear site-specific permissions like "Allow this site to open popups"
|
|
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
|
.getService(Components.interfaces.nsIPermissionManager);
|
|
pm.removeAll();
|
|
|
|
// Clear site-specific settings like page-zoom level
|
|
var cps = Components.classes["@mozilla.org/content-pref/service;1"]
|
|
.getService(Components.interfaces.nsIContentPrefService2);
|
|
cps.removeAllDomains(null);
|
|
|
|
// Clear "Never remember passwords for this site", which is not handled by
|
|
// the permission manager
|
|
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
|
.getService(Components.interfaces.nsILoginManager);
|
|
var hosts = pwmgr.getAllDisabledHosts();
|
|
for each (var host in hosts) {
|
|
pwmgr.setLoginSavingEnabled(host, true);
|
|
}
|
|
},
|
|
|
|
get canClear()
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// "Static" members
|
|
Sanitizer.prefDomain = "privacy.sanitize.";
|
|
Sanitizer.prefShutdown = "sanitizeOnShutdown";
|
|
Sanitizer.prefDidShutdown = "didShutdownSanitize";
|
|
|
|
// Time span constants corresponding to values of the privacy.sanitize.timeSpan
|
|
// pref. Used to determine how much history to clear, for various items
|
|
Sanitizer.TIMESPAN_EVERYTHING = 0;
|
|
Sanitizer.TIMESPAN_HOUR = 1;
|
|
Sanitizer.TIMESPAN_2HOURS = 2;
|
|
Sanitizer.TIMESPAN_4HOURS = 3;
|
|
Sanitizer.TIMESPAN_TODAY = 4;
|
|
|
|
// Return a 2 element array representing the start and end times,
|
|
// in the uSec-since-epoch format that PRTime likes. If we should
|
|
// clear everything, return null. Use ts if it is defined; otherwise
|
|
// use the timeSpan pref.
|
|
Sanitizer.getClearRange = function (ts) {
|
|
if (ts === undefined)
|
|
ts = Sanitizer.prefs.getIntPref("timeSpan");
|
|
if (ts === Sanitizer.TIMESPAN_EVERYTHING)
|
|
return null;
|
|
|
|
// PRTime is microseconds while JS time is milliseconds
|
|
var endDate = Date.now() * 1000;
|
|
switch (ts) {
|
|
case Sanitizer.TIMESPAN_HOUR :
|
|
var startDate = endDate - 3600000000; // 1*60*60*1000000
|
|
break;
|
|
case Sanitizer.TIMESPAN_2HOURS :
|
|
startDate = endDate - 7200000000; // 2*60*60*1000000
|
|
break;
|
|
case Sanitizer.TIMESPAN_4HOURS :
|
|
startDate = endDate - 14400000000; // 4*60*60*1000000
|
|
break;
|
|
case Sanitizer.TIMESPAN_TODAY :
|
|
var d = new Date(); // Start with today
|
|
d.setHours(0); // zero us back to midnight...
|
|
d.setMinutes(0);
|
|
d.setSeconds(0);
|
|
startDate = d.valueOf() * 1000; // convert to epoch usec
|
|
break;
|
|
default:
|
|
throw "Invalid time span for clear private data: " + ts;
|
|
}
|
|
return [startDate, endDate];
|
|
};
|
|
|
|
Sanitizer._prefs = null;
|
|
Sanitizer.__defineGetter__("prefs", function()
|
|
{
|
|
return Sanitizer._prefs ? Sanitizer._prefs
|
|
: Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
|
.getService(Components.interfaces.nsIPrefService)
|
|
.getBranch(Sanitizer.prefDomain);
|
|
});
|
|
|
|
// Shows sanitization UI
|
|
Sanitizer.showUI = function(aParentWindow)
|
|
{
|
|
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
|
.getService(Components.interfaces.nsIWindowWatcher);
|
|
#ifdef XP_MACOSX
|
|
ww.openWindow(null, // make this an app-modal window on Mac
|
|
#else
|
|
ww.openWindow(aParentWindow,
|
|
#endif
|
|
"chrome://browser/content/sanitize.xul",
|
|
"Sanitize",
|
|
"chrome,titlebar,dialog,centerscreen,modal",
|
|
null);
|
|
};
|
|
|
|
/**
|
|
* Deletes privacy sensitive data in a batch, optionally showing the
|
|
* sanitize UI, according to user preferences
|
|
*/
|
|
Sanitizer.sanitize = function(aParentWindow)
|
|
{
|
|
Sanitizer.showUI(aParentWindow);
|
|
};
|
|
|
|
Sanitizer.onStartup = function()
|
|
{
|
|
// we check for unclean exit with pending sanitization
|
|
Sanitizer._checkAndSanitize();
|
|
};
|
|
|
|
Sanitizer.onShutdown = function()
|
|
{
|
|
// we check if sanitization is needed and perform it
|
|
Sanitizer._checkAndSanitize();
|
|
};
|
|
|
|
// this is called on startup and shutdown, to perform pending sanitizations
|
|
Sanitizer._checkAndSanitize = function()
|
|
{
|
|
const prefs = Sanitizer.prefs;
|
|
if (prefs.getBoolPref(Sanitizer.prefShutdown) &&
|
|
!prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) {
|
|
// this is a shutdown or a startup after an unclean exit
|
|
var s = new Sanitizer();
|
|
s.prefDomain = "privacy.clearOnShutdown.";
|
|
s.sanitize().then(function() {
|
|
prefs.setBoolPref(Sanitizer.prefDidShutdown, true);
|
|
});
|
|
}
|
|
};
|