Bug 1524883 - Clear storageAccessAPI permissions when history is cleared. r=johannh,Ehsan

When history is cleared, clear the flag that indicates a user has visited the domain.

Differential Revision: https://phabricator.services.mozilla.com/D24404

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Erica Wright 2019-03-28 18:44:08 +00:00
parent e5f97940c5
commit fccf274cc5
9 changed files with 234 additions and 1 deletions

View File

@ -349,7 +349,8 @@ var Sanitizer = {
let refObj = {};
TelemetryStopwatch.start("FX_SANITIZE_HISTORY", refObj);
await clearData(range, Ci.nsIClearDataService.CLEAR_HISTORY |
Ci.nsIClearDataService.CLEAR_SESSION_HISTORY);
Ci.nsIClearDataService.CLEAR_SESSION_HISTORY |
Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS);
TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj);
},
},

View File

@ -2156,6 +2156,25 @@ nsPermissionManager::RemoveByType(const nsACString& aType) {
});
}
NS_IMETHODIMP
nsPermissionManager::RemoveByTypeSince(const nsACString& aType,
int64_t aModificationTime) {
ENSURE_NOT_CHILD_PROCESS;
int32_t typeIndex = GetTypeIndex(aType, false);
// If type == -1, the type isn't known,
// so just return NS_OK
if (typeIndex == -1) {
return NS_OK;
}
return RemovePermissionEntries(
[typeIndex, aModificationTime](const PermissionEntry& aPermEntry) {
return uint32_t(typeIndex) == aPermEntry.mType &&
aModificationTime <= aPermEntry.mModificationTime;
});
}
void nsPermissionManager::CloseDB(bool aRebuildOnSuccess) {
// Null the statements, this will finalize them.
mStmtInsert = nullptr;

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test() {
Services.prefs.setCharPref("permissions.manager.defaultsUrl", "");
// initialize the permission manager service
let pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
Assert.equal(perm_count(), 0);
// add some permissions
let uri = Services.io.newURI("http://amazon.com:8080/foobarbaz");
let uri2 = Services.io.newURI("http://google.com:2048/quxx");
let uri3 = Services.io.newURI("https://google.com/search");
pm.add(uri, "apple", 3);
pm.add(uri, "pear", 1);
pm.add(uri, "cucumber", 1);
// sleep briefly, then record the time - we'll remove some permissions since then.
await new Promise(resolve => do_timeout(20, resolve));
let since = Date.now();
// *sob* - on Windows at least, the now recorded by nsPermissionManager.cpp
// might be a couple of ms *earlier* than what JS sees. So another sleep
// to ensure our |since| is greater than the time of the permissions we
// are now adding. Sadly this means we'll never be able to test when since
// exactly equals the modTime, but there you go...
await new Promise(resolve => do_timeout(20, resolve));
pm.add(uri2, "apple", 2);
pm.add(uri2, "pear", 2);
pm.add(uri3, "cucumber", 3);
pm.add(uri3, "apple", 1);
Assert.equal(perm_count(), 7);
pm.removeByTypeSince("apple", since);
Assert.equal(perm_count(), 5);
Assert.equal(pm.testPermission(uri, "pear"), 1);
Assert.equal(pm.testPermission(uri2, "pear"), 2);
Assert.equal(pm.testPermission(uri, "apple"), 3);
Assert.equal(pm.testPermission(uri2, "apple"), 0);
Assert.equal(pm.testPermission(uri3, "apple"), 0);
Assert.equal(pm.testPermission(uri, "cucumber"), 1);
Assert.equal(pm.testPermission(uri3, "cucumber"), 3);
pm.removeByTypeSince("cucumber", since);
Assert.equal(perm_count(), 4);
Assert.equal(pm.testPermission(uri, "pear"), 1);
Assert.equal(pm.testPermission(uri2, "pear"), 2);
Assert.equal(pm.testPermission(uri, "apple"), 3);
Assert.equal(pm.testPermission(uri2, "apple"), 0);
Assert.equal(pm.testPermission(uri3, "apple"), 0);
Assert.equal(pm.testPermission(uri, "cucumber"), 1);
Assert.equal(pm.testPermission(uri3, "cucumber"), 0);
pm.removeByTypeSince("pear", since);
Assert.equal(perm_count(), 3);
Assert.equal(pm.testPermission(uri, "pear"), 1);
Assert.equal(pm.testPermission(uri2, "pear"), 0);
Assert.equal(pm.testPermission(uri, "apple"), 3);
Assert.equal(pm.testPermission(uri2, "apple"), 0);
Assert.equal(pm.testPermission(uri3, "apple"), 0);
Assert.equal(pm.testPermission(uri, "cucumber"), 1);
Assert.equal(pm.testPermission(uri3, "cucumber"), 0);
function perm_count() {
let enumerator = pm.enumerator;
let count = 0;
while (enumerator.hasMoreElements()) {
count++;
enumerator.getNext();
}
return count;
}
});

View File

@ -26,6 +26,7 @@ skip-if = true # Bug 863738
[test_permmanager_notifications.js]
[test_permmanager_removeall.js]
[test_permmanager_removebytype.js]
[test_permmanager_removebytypesince.js]
[test_permmanager_removesince.js]
[test_permmanager_removeforapp.js]
[test_permmanager_load_invalid_entries.js]

View File

@ -190,6 +190,14 @@ interface nsIPermissionManager : nsISupports
*/
void removeByType(in ACString type);
/**
* Clear all permissions of the passed type added since the specified time.
* @param type a case-sensitive ASCII string, identifying the permission.
* @param since a unix timestamp representing the number of milliseconds from
* Jan 1, 1970 00:00:00 UTC.
*/
void removeByTypeSince(in ACString type, in int64_t since);
/**
* Test whether a website has permission to perform the given action.
* This function will perform a pref lookup to permissions.default.<type>

View File

@ -516,6 +516,45 @@ const PushNotificationsCleaner = {
},
};
const StorageAccessCleaner = {
deleteByHost(aHost, aOriginAttributes) {
return new Promise(aResolve => {
for (let perm of Services.perms.enumerator) {
if (perm.type == "storageAccessAPI") {
let toBeRemoved = false;
try {
toBeRemoved = Services.eTLD.hasRootDomain(perm.principal.URI.host,
aHost);
} catch (ex) {
continue;
}
if (!toBeRemoved) {
continue;
}
try {
Services.perms.removePermission(perm);
} catch (ex) {
Cu.reportError(ex);
}
}
}
aResolve();
});
},
deleteByRange(aFrom, aTo) {
Services.perms.removeByTypeSince("storageAccessAPI", aFrom / 1000);
return Promise.resolve();
},
deleteAll() {
Services.perms.removeByType("storageAccessAPI");
return Promise.resolve();
},
};
const HistoryCleaner = {
deleteByHost(aHost, aOriginAttributes) {
return PlacesUtils.history.removeByFilter({ host: "." + aHost });
@ -796,6 +835,9 @@ const FLAGS_MAP = [
{ flag: Ci.nsIClearDataService.CLEAR_REPORTS,
cleaner: ReportsCleaner },
{ flag: Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS,
cleaner: StorageAccessCleaner },
];
this.ClearDataService = function() {

View File

@ -189,6 +189,11 @@ interface nsIClearDataService : nsISupports
*/
const uint32_t CLEAR_REPORTS = 1 << 19;
/**
* StorageAccessAPI flag, which indicates user interaction.
*/
const uint32_t CLEAR_STORAGE_ACCESS = 1 << 20;
/**
* Use this value to delete all the data.
*/

View File

@ -0,0 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests for permissions
*/
"use strict";
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Test that only the storageAccessAPI gets removed.
add_task(async function test_removing_storage_permission() {
const uri = Services.io.newURI("https://example.net");
const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.addFromPrincipal(principal, "storageAccessAPI", Services.perms.ALLOW_ACTION);
Services.perms.addFromPrincipal(principal, "cookie", Services.perms.ALLOW_ACTION);
Assert.equal(Services.perms.testExactPermissionFromPrincipal(principal, "storageAccessAPI"), Services.perms.ALLOW_ACTION, "There is a storageAccessAPI permission set");
await new Promise(aResolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS, value => {
Assert.equal(value, 0);
aResolve();
});
});
Assert.equal(Services.perms.testExactPermissionFromPrincipal(principal, "storageAccessAPI"), Services.perms.UNKNOWN_ACTION, "the storageAccessAPI permission has been removed");
Assert.equal(Services.perms.testExactPermissionFromPrincipal(principal, "cookie"), Services.perms.ALLOW_ACTION, "the cookie permission has not been removed");
await new Promise(aResolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => aResolve());
});
});
// Test that the storageAccessAPI gets removed from a particular principal
add_task(async function test_removing_storage_permission_from_principal() {
const uri = Services.io.newURI("https://example.net");
const principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
const anotherUri = Services.io.newURI("https://example.com");
const anotherPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(anotherUri, {});
Services.perms.addFromPrincipal(principal, "storageAccessAPI", Services.perms.ALLOW_ACTION);
Services.perms.addFromPrincipal(anotherPrincipal, "storageAccessAPI", Services.perms.ALLOW_ACTION);
Assert.equal(Services.perms.testExactPermissionFromPrincipal(principal, "storageAccessAPI"), Services.perms.ALLOW_ACTION, "storageAccessAPI permission has been added to the first principal");
Assert.equal(Services.perms.testExactPermissionFromPrincipal(anotherPrincipal, "storageAccessAPI"), Services.perms.ALLOW_ACTION, "storageAccessAPI permission has been added to the second principal");
await new Promise(aResolve => {
Services.clearData.deleteDataFromPrincipal(principal, true /* user request */,
Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS, value => {
Assert.equal(value, 0);
aResolve();
});
});
Assert.equal(Services.perms.testExactPermissionFromPrincipal(principal, "storageAccessAPI"), Services.perms.UNKNOWN_ACTION, "storageAccessAPI permission has been removed from the first principal");
Assert.equal(Services.perms.testExactPermissionFromPrincipal(anotherPrincipal, "storageAccessAPI"), Services.perms.ALLOW_ACTION, "storageAccessAPI permission has not been removed from the second principal");
await new Promise(aResolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PERMISSIONS, value => aResolve());
});
});

View File

@ -8,3 +8,4 @@ support-files =
[test_downloads.js]
[test_passwords.js]
[test_permissions.js]
[test_storage_permission.js]