Bug 1363014 - Implement browsingData.remove WebExtension API method on android. r=sebastian, bsilverberg
MozReview-Commit-ID: 2ipz1wqGpxc
--- a/mobile/android/components/extensions/ext-browsingData.js
+++ b/mobile/android/components/extensions/ext-browsingData.js
@@ -6,23 +6,22 @@ Cu.import("resource://gre/modules/Task.j
XPCOMUtils.defineLazyModuleGetter(this, "Sanitizer",
"resource://gre/modules/Sanitizer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences",
"resource://gre/modules/SharedPreferences.jsm");
-let clearCookies = async function(options) {
- if (options.originTypes &&
- (options.originTypes.protectedWeb || options.originTypes.extension)) {
- return Promise.reject(
- {message: "Firefox does not support protectedWeb or extension as originTypes."});
- }
+const clearCache = () => {
+ // Clearing the cache does not support timestamps.
+ return Sanitizer.clearItem("cache");
+};
+const clearCookies = async function(options) {
let cookieMgr = Services.cookies;
let yieldCounter = 0;
const YIELD_PERIOD = 10;
if (options.since) {
// Convert it to microseconds
let since = options.since * 1000;
// Iterate through the cookies and delete any created after our cutoff.
@@ -41,18 +40,63 @@ let clearCookies = async function(option
}
}
} else {
// Remove everything.
cookieMgr.removeAll();
}
};
+const clearDownloads = options => {
+ return Sanitizer.clearItem("downloadHistory", options.since);
+};
+
+const clearFormData = options => {
+ return Sanitizer.clearItem("formdata", options.since);
+};
+
+const doRemoval = (options, dataToRemove, extension) => {
+ if (options.originTypes &&
+ (options.originTypes.protectedWeb || options.originTypes.extension)) {
+ return Promise.reject(
+ {message: "Firefox does not support protectedWeb or extension as originTypes."});
+ }
+
+ let removalPromises = [];
+ let invalidDataTypes = [];
+ for (let dataType in dataToRemove) {
+ if (dataToRemove[dataType]) {
+ switch (dataType) {
+ case "cache":
+ removalPromises.push(clearCache());
+ break;
+ case "cookies":
+ removalPromises.push(clearCookies(options));
+ break;
+ case "downloads":
+ removalPromises.push(clearDownloads(options));
+ break;
+ case "formData":
+ removalPromises.push(clearFormData(options));
+ break;
+ default:
+ invalidDataTypes.push(dataType);
+ }
+ }
+ }
+ if (extension && invalidDataTypes.length) {
+ extension.logger.warn(
+ `Firefox does not support dataTypes: ${invalidDataTypes.toString()}.`);
+ }
+ return Promise.all(removalPromises);
+};
+
this.browsingData = class extends ExtensionAPI {
getAPI(context) {
+ let {extension} = context;
return {
browsingData: {
settings() {
const PREF_DOMAIN = "android.not_a_preference.privacy.clear";
const PREF_KEY_PREFIX = "private.data.";
// The following prefs are the only ones in Firefox that match corresponding
// values used by Chrome when returning settings.
const PREF_LIST = ["cache", "history", "formdata", "cookies_sessions", "downloadFiles"];
@@ -83,24 +127,27 @@ this.browsingData = class extends Extens
// Firefox doesn't have the same concept of dataRemovalPermitted
// as Chrome, so it will always be true.
dataRemovalPermitted[name] = true;
}
// We do not provide option to delete history by time
// so, since value is given 0, which means Everything
return Promise.resolve({options: {since: 0}, dataToRemove, dataRemovalPermitted});
},
- removeCookies(options) {
- return clearCookies(options);
+ remove(options, dataToRemove) {
+ return doRemoval(options, dataToRemove, extension);
},
removeCache(options) {
- return Sanitizer.clearItem("cache");
+ return doRemoval(options, {cache: true});
+ },
+ removeCookies(options) {
+ return doRemoval(options, {cookies: true});
},
removeDownloads(options) {
- return Sanitizer.clearItem("downloadHistory", options.since);
+ return doRemoval(options, {downloads: true});
},
removeFormData(options) {
- return Sanitizer.clearItem("formdata", options.since);
+ return doRemoval(options, {formData: true});
},
},
};
}
};
--- a/mobile/android/components/extensions/schemas/browsing_data.json
+++ b/mobile/android/components/extensions/schemas/browsing_data.json
@@ -157,17 +157,16 @@
}
]
},
{
"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",
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_cookies_cache.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_cookies_cache.html
@@ -40,17 +40,21 @@ async function setUpCookies() {
// Add a cookie which will end up with a more recent creationTime.
addCookie(COOKIE);
}
add_task(async function testCookies() {
function background() {
browser.test.onMessage.addListener(async (msg, options) => {
- await browser.browsingData.removeCookies(options);
+ if (msg == "removeCookies") {
+ await browser.browsingData.removeCookies(options);
+ } else {
+ await browser.browsingData.remove(options, {cookies: true});
+ }
browser.test.sendMessage("cookiesRemoved");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["browsingData"],
@@ -84,25 +88,28 @@ add_task(async function testCookies() {
ok(!Services.cookies.cookieExists(COOKIE), `Cookie ${COOKIE.name} was removed.`);
ok(!Services.cookies.cookieExists(oldCookie), `Cookie ${oldCookie.name} was removed.`);
}
await extension.startup();
await testRemovalMethod("removeCookies");
+ await testRemovalMethod("remove");
await extension.unload();
});
add_task(async function testCache() {
function background() {
browser.test.onMessage.addListener(async msg => {
if (msg == "removeCache") {
await browser.browsingData.removeCache({});
+ } else {
+ await browser.browsingData.remove({}, {cache: true});
}
browser.test.sendMessage("cacheRemoved");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
@@ -128,15 +135,16 @@ add_task(async function testCache() {
extension.sendMessage(method);
await awaitNotification;
await extension.awaitMessage("cacheRemoved");
}
await extension.startup();
await testRemovalMethod("removeCache");
+ await testRemovalMethod("remove");
await extension.unload();
});
</script>
</body>
</html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_downloads.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_downloads.html
@@ -72,17 +72,21 @@ async function setupDownloads() {
downloadsList = await Downloads.getList(Downloads.ALL);
is((await downloadsList.getAll()).length, 4, "4 fake downloads added.");
checkDownloads();
}
add_task(async function testDownloads() {
function background() {
browser.test.onMessage.addListener(async (msg, options) => {
- await browser.browsingData.removeDownloads(options);
+ if (msg == "removeDownloads") {
+ await browser.browsingData.removeDownloads(options);
+ } else {
+ await browser.browsingData.remove(options, {downloads: true});
+ }
browser.test.sendMessage("downloadsRemoved");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["browsingData"],
@@ -107,15 +111,16 @@ add_task(async function testDownloads()
extension.sendMessage(method, {since: REFERENCE_DATE - 100000});
await extension.awaitMessage("downloadsRemoved");
await checkDownloads(false, false);
}
await extension.startup();
await testRemovalMethod("removeDownloads");
+ await testRemovalMethod("remove");
await extension.unload();
});
</script>
</body>
</html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_formdata.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_formdata.html
@@ -89,17 +89,21 @@ async function setupFormHistory() {
await countEntries("reference", "Checking for 10minutes form history entry creation", 1);
await countEntries("10secondsAgo", "Checking for 1hour form history entry creation", 1);
await countEntries("10minutesAgo", "Checking for 1hour10minutes form history entry creation", 1);
}
add_task(async function testFormData() {
function background() {
browser.test.onMessage.addListener(async (msg, options) => {
- await browser.browsingData.removeFormData(options);
+ if (msg == "removeFormData") {
+ await browser.browsingData.removeFormData(options);
+ } else {
+ await browser.browsingData.remove(options, {formData: true});
+ }
browser.test.sendMessage("formDataRemoved");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["browsingData"],
@@ -133,15 +137,16 @@ add_task(async function testFormData() {
await countEntries("reference", "reference form entry should be deleted.", 0);
await countEntries("10secondsAgo", "10secondsAgo form entry should be deleted.", 0);
await countEntries("10minutesAgo", "10minutesAgo form entry should be deleted.", 0);
}
await extension.startup();
await testRemovalMethod("removeFormData");
+ await testRemovalMethod("remove");
await extension.unload();
});
</script>
</body>
</html>