Bug 1320986 - Implement browsingData.settings WebExtensions API method, r?aswan draft
authorBob Silverberg <bsilverberg@mozilla.com>
Mon, 28 Nov 2016 09:17:04 -0500
changeset 447062 b9d1d536d68ab515d4725debfc9461ea30a6f847
parent 444725 8387a4ada9a5c4cab059d8fafe0f8c933e83c149
child 448753 99ed9e7478e5e6c5fabce1edbc82e294d16412a4
child 448967 0ed80a59ab8b778b7b5d79140f8da63127a1a622
child 448969 14452e53894974eab201df667b7560365dff926c
child 449267 acca0d2867d5a5de6eec3b803079e384d970d9a3
child 449270 d638a02ba65677357c75494c445ef9e627588b92
child 449278 99d61c072c525866a100b511d7b07ebbdfc8b339
push id37969
push userbmo:bob.silverberg@gmail.com
push dateFri, 02 Dec 2016 14:42:33 +0000
reviewersaswan
bugs1320986
milestone53.0a1
Bug 1320986 - Implement browsingData.settings WebExtensions API method, r?aswan MozReview-Commit-ID: JqUm77vFod2
browser/components/extensions/ext-browsingData.js
browser/components/extensions/extensions-browser.manifest
browser/components/extensions/jar.mn
browser/components/extensions/schemas/browsing_data.json
browser/components/extensions/schemas/jar.mn
browser/components/extensions/test/xpcshell/test_ext_browsingData_settings.js
browser/components/extensions/test/xpcshell/xpcshell.ini
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-browsingData.js
@@ -0,0 +1,39 @@
+"use strict";
+
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Sanitizer",
+                                  "resource:///modules/Sanitizer.jsm");
+
+extensions.registerSchemaAPI("browsingData", "addon_parent", context => {
+  return {
+    browsingData: {
+      settings() {
+        const PREF_DOMAIN = "privacy.cpd.";
+        // The following prefs are the only ones in Firefox that match corresponding
+        // values used by Chrome when rerturning settings.
+        const PREF_LIST = ["cache", "cookies", "history", "formdata", "downloads"];
+
+        // since will be the start of what is returned by Sanitizer.getClearRange
+        // divided by 1000 to convert to ms.
+        let since = Sanitizer.getClearRange()[0] / 1000;
+        let options = {since};
+
+        let dataToRemove = {};
+        let dataRemovalPermitted = {};
+
+        for (let item of PREF_LIST) {
+          dataToRemove[item] = Preferences.get(`${PREF_DOMAIN}${item}`);
+          // Firefox doesn't have the same concept of dataRemovalPermitted
+          // as Chrome, so it will always be true.
+          dataRemovalPermitted[item] = true;
+        }
+        // formData has a different case than the pref formdata.
+        dataToRemove.formData = Preferences.get(`${PREF_DOMAIN}formdata`);
+        dataRemovalPermitted.formData = true;
+
+        return Promise.resolve({options, dataToRemove, dataRemovalPermitted});
+      },
+    },
+  };
+});
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -1,11 +1,12 @@
 # scripts
 category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
 category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
+category webextension-scripts browsingData chrome://browser/content/ext-browsingData.js
 category webextension-scripts commands chrome://browser/content/ext-commands.js
 category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts history chrome://browser/content/ext-history.js
 category webextension-scripts omnibox chrome://browser/content/ext-omnibox.js
 category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
 category webextension-scripts sessions chrome://browser/content/ext-sessions.js
 category webextension-scripts tabs chrome://browser/content/ext-tabs.js
@@ -15,16 +16,17 @@ category webextension-scripts windows ch
 # scripts that must run in the same process as addon code.
 category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
 category webextension-scripts-addon omnibox chrome://browser/content/ext-c-omnibox.js
 category webextension-scripts-addon tabs chrome://browser/content/ext-c-tabs.js
 
 # schemas
 category webextension-schemas bookmarks chrome://browser/content/schemas/bookmarks.json
 category webextension-schemas browser_action chrome://browser/content/schemas/browser_action.json
+category webextension-schemas browsing_data chrome://browser/content/schemas/browsing_data.json
 category webextension-schemas commands chrome://browser/content/schemas/commands.json
 category webextension-schemas context_menus chrome://browser/content/schemas/context_menus.json
 category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
 category webextension-schemas history chrome://browser/content/schemas/history.json
 category webextension-schemas omnibox chrome://browser/content/schemas/omnibox.json
 category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
 category webextension-schemas sessions chrome://browser/content/schemas/sessions.json
 category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -9,16 +9,17 @@ browser.jar:
     content/browser/extension-mac-panel.css
 #endif
 #ifdef XP_WIN
     content/browser/extension-win-panel.css
 #endif
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
+    content/browser/ext-browsingData.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-history.js
     content/browser/ext-omnibox.js
     content/browser/ext-pageAction.js
     content/browser/ext-sessions.js
     content/browser/ext-tabs.js
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/browsing_data.json
@@ -0,0 +1,421 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+  {
+    "namespace": "manifest",
+    "types": [
+      {
+        "$extend": "Permission",
+        "choices": [{
+          "type": "string",
+          "enum": [
+            "browsingData"
+          ]
+        }]
+      }
+    ]
+  },
+  {
+    "namespace": "browsingData",
+    "description": "Use the <code>chrome.browsingData</code> API to remove browsing data from a user's local profile.",
+    "permissions": ["browsingData"],
+    "types": [
+      {
+        "id": "RemovalOptions",
+        "type": "object",
+        "description": "Options that determine exactly what data will be removed.",
+        "properties": {
+          "since": {
+            "$ref": "extensionTypes.Date",
+            "optional": true,
+            "description": "Remove data accumulated on or after this date, represented in milliseconds since the epoch (accessible via the <code>getTime</code> method of the JavaScript <code>Date</code> object). If absent, defaults to 0 (which would remove all browsing data)."
+          },
+          "originTypes": {
+            "type": "object",
+            "optional": true,
+            "description": "An object whose properties specify which origin types ought to be cleared. If this object isn't specified, it defaults to clearing only \"unprotected\" origins. Please ensure that you <em>really</em> want to remove application data before adding 'protectedWeb' or 'extensions'.",
+            "properties": {
+              "unprotectedWeb": {
+                "type": "boolean",
+                "optional": true,
+                "description": "Normal websites."
+              },
+              "protectedWeb": {
+                "type": "boolean",
+                "optional": true,
+                "description": "Websites that have been installed as hosted applications (be careful!)."
+              },
+              "extension": {
+                "type": "boolean",
+                "optional": true,
+                "description": "Extensions and packaged applications a user has installed (be _really_ careful!)."
+              }
+            }
+          }
+        }
+      },
+      {
+        "id": "DataTypeSet",
+        "type": "object",
+        "description": "A set of data types. Missing data types are interpreted as <code>false</code>.",
+        "properties": {
+          "cache": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's cache. Note: when removing data, this clears the <em>entire</em> cache: it is not limited to the range you specify."
+          },
+          "cookies": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's cookies."
+          },
+          "downloads": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's download list."
+          },
+          "formData": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's stored form data."
+          },
+          "history": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's history."
+          },
+          "indexedDB": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' IndexedDB data."
+          },
+          "localStorage": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' local storage data."
+          },
+          "serverBoundCertificates": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Server-bound certificates."
+          },
+          "passwords": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Stored passwords."
+          },
+          "pluginData": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Plugins' data."
+          },
+          "serviceWorkers": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Service Workers."
+          }
+        }
+      }
+    ],
+    "functions": [
+      {
+        "name": "settings",
+        "description": "Reports which types of data are currently selected in the 'Clear browsing data' settings UI.  Note: some of the data types included in this API are not available in the settings UI, and some UI settings control more than one data type listed here.",
+        "type": "function",
+        "async": "callback",
+        "parameters": [
+          {
+            "name": "callback",
+            "type": "function",
+            "parameters": [
+              {
+                "name": "result",
+                "type": "object",
+                "properties": {
+                  "options": {
+                    "$ref": "RemovalOptions"
+                  },
+                  "dataToRemove": {
+                    "$ref": "DataTypeSet",
+                    "description": "All of the types will be present in the result, with values of <code>true</code> if they are both selected to be removed and permitted to be removed, otherwise <code>false</code>."
+                  },
+                  "dataRemovalPermitted": {
+                    "$ref": "DataTypeSet",
+                    "description": "All of the types will be present in the result, with values of <code>true</code> if they are permitted to be removed (e.g., by enterprise policy) and <code>false</code> if not."
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "remove",
+        "description": "Clears various types of browsing data stored in a user's profile.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "dataToRemove",
+            "$ref": "DataTypeSet",
+            "description": "The set of data types to remove."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when deletion has completed.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeAppcache",
+        "description": "Clears websites' appcache data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' appcache data has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeCache",
+        "description": "Clears the browser's cache.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's cache has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeCookies",
+        "description": "Clears the browser's cookies and server-bound certificates modified within a particular timeframe.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's cookies and server-bound certificates have been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeDownloads",
+        "description": "Clears the browser's list of downloaded files (<em>not</em> the downloaded files themselves).",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's list of downloaded files has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeFileSystems",
+        "description": "Clears websites' file system data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' file systems have been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeFormData",
+        "description": "Clears the browser's stored form data (autofill).",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's form data has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeHistory",
+        "description": "Clears the browser's history.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's history has cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeIndexedDB",
+        "description": "Clears websites' IndexedDB data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' IndexedDB data has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeLocalStorage",
+        "description": "Clears websites' local storage data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' local storage has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removePluginData",
+        "description": "Clears plugins' data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when plugins' data has been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removePasswords",
+        "description": "Clears the browser's stored passwords.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the browser's passwords have been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
+        "name": "removeWebSQL",
+        "description": "Clears websites' WebSQL data.",
+        "type": "function",
+        "async": "callback",
+        "unsupported": true,
+        "parameters": [
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when websites' WebSQL databases have been cleared.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      }
+    ]
+  }
+]
--- a/browser/components/extensions/schemas/jar.mn
+++ b/browser/components/extensions/schemas/jar.mn
@@ -1,15 +1,16 @@
 # 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/.
 
 browser.jar:
     content/browser/schemas/bookmarks.json
     content/browser/schemas/browser_action.json
+    content/browser/schemas/browsing_data.json
     content/browser/schemas/commands.json
     content/browser/schemas/context_menus.json
     content/browser/schemas/context_menus_internal.json
     content/browser/schemas/history.json
     content/browser/schemas/omnibox.json
     content/browser/schemas/page_action.json
     content/browser/schemas/sessions.json
     content/browser/schemas/tabs.json
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/xpcshell/test_ext_browsingData_settings.js
@@ -0,0 +1,76 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+XPCOMUtils.defineLazyModuleGetter(this, "Sanitizer",
+                                  "resource:///modules/Sanitizer.jsm");
+
+const PREF_DOMAIN = "privacy.cpd.";
+
+add_task(function* testSettings() {
+  function background() {
+    browser.test.onMessage.addListener(msg => {
+      browser.browsingData.settings().then(settings => {
+        browser.test.sendMessage("settings", settings);
+      });
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      permissions: ["browsingData"],
+    },
+  });
+
+  yield extension.startup();
+
+  let branch = Services.prefs.getBranch(PREF_DOMAIN);
+
+  extension.sendMessage("settings");
+  let settings = yield extension.awaitMessage("settings");
+
+  let since = Sanitizer.getClearRange()[0] / 1000;
+
+  // Because it is based on the current timestamp, we cannot know the exact
+  // value to expect for since, so allow a 10s variance.
+  ok(Math.abs(settings.options.since - since) < 10000,
+     "settings.options contains the expected since value.");
+
+  let dataTypeSet = settings.dataToRemove;
+  for (let key of Object.keys(dataTypeSet)) {
+    equal(branch.getBoolPref(key.toLowerCase()), dataTypeSet[key], `${key} property of dataToRemove matches the expected pref.`);
+  }
+
+  dataTypeSet = settings.dataRemovalPermitted;
+  for (let key of Object.keys(dataTypeSet)) {
+    equal(true, dataTypeSet[key], `${key} property of dataRemovalPermitted is true.`);
+  }
+
+  // Explicitly set a pref to both true and false and then check.
+  const SINGLE_PREF = "cache";
+
+  do_register_cleanup(() => {
+    branch.clearUserPref(SINGLE_PREF);
+  });
+
+  branch.setBoolPref(SINGLE_PREF, true);
+
+  extension.sendMessage("settings");
+  settings = yield extension.awaitMessage("settings");
+
+  equal(settings.dataToRemove[SINGLE_PREF], true, "Preference that was set to true returns true.");
+
+  branch.setBoolPref(SINGLE_PREF, false);
+
+  extension.sendMessage("settings");
+  settings = yield extension.awaitMessage("settings");
+
+  equal(settings.dataToRemove[SINGLE_PREF], false, "Preference that was set to false returns false.");
+
+  do_register_cleanup(() => {
+    branch.clearUserPref(SINGLE_PREF);
+  });
+
+  yield extension.unload();
+});
--- a/browser/components/extensions/test/xpcshell/xpcshell.ini
+++ b/browser/components/extensions/test/xpcshell/xpcshell.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
 tags = webextensions
 
 [test_ext_bookmarks.js]
+[test_ext_browsingData_settings.js]
 [test_ext_history.js]
 [test_ext_manifest_commands.js]
 [test_ext_manifest_omnibox.js]
 [test_ext_manifest_permissions.js]