summaryrefslogtreecommitdiffstats
path: root/comm/mail/base/content/sanitize.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/mail/base/content/sanitize.js241
1 files changed, 241 insertions, 0 deletions
diff --git a/comm/mail/base/content/sanitize.js b/comm/mail/base/content/sanitize.js
new file mode 100644
index 0000000000..68510faeac
--- /dev/null
+++ b/comm/mail/base/content/sanitize.js
@@ -0,0 +1,241 @@
+/* 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/. */
+
+var { PlacesUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/PlacesUtils.sys.mjs"
+);
+var { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+
+function Sanitizer() {}
+Sanitizer.prototype = {
+ // warning to the caller: this one may raise an exception (e.g. bug #265028)
+ clearItem(aItemName) {
+ if (this.items[aItemName].canClear) {
+ this.items[aItemName].clear();
+ }
+ },
+
+ canClearItem(aItemName) {
+ return this.items[aItemName].canClear;
+ },
+
+ prefDomain: "",
+
+ getNameFromPreference(aPreferenceName) {
+ return aPreferenceName.substr(this.prefDomain.length);
+ },
+
+ /**
+ * Deletes privacy sensitive data in a batch, according to user preferences
+ *
+ * @returns null if everything's fine; an object in the form
+ * { itemName: error, ... } on (partial) failure
+ */
+ sanitize() {
+ var branch = Services.prefs.getBranch(this.prefDomain);
+ var errors = null;
+
+ // Cache the range of times to clear
+ if (this.ignoreTimespan) {
+ // If we ignore timespan, clear everything.
+ var range = null;
+ } else {
+ range = this.range || Sanitizer.getClearRange();
+ }
+
+ for (var itemName in this.items) {
+ var item = this.items[itemName];
+ item.range = range;
+ if ("clear" in item && item.canClear && branch.getBoolPref(itemName)) {
+ // 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
+ try {
+ item.clear();
+ } catch (er) {
+ if (!errors) {
+ errors = {};
+ }
+ errors[itemName] = er;
+ dump("Error sanitizing " + itemName + ": " + er + "\n");
+ }
+ }
+ }
+ return errors;
+ },
+
+ // 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() {
+ try {
+ // Cache doesn't consult timespan, nor does it have the
+ // facility for timespan-based eviction. Wipe it.
+ Services.cache2.clear();
+ } catch (ex) {}
+ },
+
+ get canClear() {
+ return true;
+ },
+ },
+
+ cookies: {
+ clear() {
+ if (this.range) {
+ // Iterate through the cookies and delete any created after our cutoff.
+ for (let cookie of Services.cookies.cookies) {
+ if (cookie.creationTime > this.range[0]) {
+ // This cookie was created after our cutoff, clear it
+ Services.cookies.remove(
+ cookie.host,
+ cookie.name,
+ cookie.path,
+ cookie.originAttributes
+ );
+ }
+ }
+ } else {
+ // Remove everything
+ Services.cookies.removeAll();
+ }
+ },
+
+ get canClear() {
+ return true;
+ },
+ },
+
+ history: {
+ clear() {
+ if (this.range) {
+ PlacesUtils.history.removeVisitsByFilter({
+ beginDate: new Date(this.range[0]),
+ endDate: new Date(this.range[1]),
+ });
+ } else {
+ PlacesUtils.history.clear();
+ }
+
+ try {
+ Services.obs.notifyObservers(null, "browser:purge-session-history");
+ } catch (e) {}
+
+ try {
+ var predictor = Cc["@mozilla.org/network/predictor;1"].getService(
+ Ci.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;
+ },
+ },
+ },
+};
+
+// "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 new Error("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 = Services.prefs.getBranch(Sanitizer.prefDomain));
+});
+
+// Shows sanitization UI
+Sanitizer.showUI = function (aParentWindow) {
+ Services.ww.openWindow(
+ AppConstants.platform == "macosx" ? null : aParentWindow,
+ "chrome://messenger/content/sanitize.xhtml",
+ "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);
+};
+
+// 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() || prefs.setBoolPref(Sanitizer.prefDidShutdown, true); // sanitize() returns null on full success
+ }
+};