Bug 1058433 - nsPermissionManager now records the mod-time of a permission and allows removal of ones modified since a specified time. r=ehsan

This commit is contained in:
Mark Hammond 2014-09-15 11:33:12 +10:00
parent d37d2ef50a
commit f9a0630114
11 changed files with 348 additions and 36 deletions

View File

@ -303,7 +303,7 @@ class Automation(object):
permDB = sqlite3.connect(os.path.join(profileDir, "permissions.sqlite"))
cursor = permDB.cursor();
cursor.execute("PRAGMA user_version=3");
cursor.execute("PRAGMA user_version=4");
# SQL copied from nsPermissionManager.cpp
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
@ -313,13 +313,14 @@ class Automation(object):
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
modificationTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)""")
# Insert desired permissions
for perm in permissions.keys():
for host,allow in permissions[perm]:
cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)",
cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0, 0)",
(host, perm, 1 if allow else 2))
# Commit and close

View File

@ -1714,12 +1714,16 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission)
getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, true);
// child processes don't care about modification time.
int64_t modificationTime = 0;
permissionManager->AddInternal(principal,
nsCString(permission.type),
permission.capability,
0,
permission.expireType,
permission.expireTime,
modificationTime,
nsPermissionManager::eNotify,
nsPermissionManager::eNoDBOperation);
#endif

View File

@ -357,7 +357,7 @@ nsPermissionManager::AppClearDataObserverInit()
// nsPermissionManager Implementation
static const char kPermissionsFileName[] = "permissions.sqlite";
#define HOSTS_SCHEMA_VERSION 3
#define HOSTS_SCHEMA_VERSION 4
static const char kHostpermFileName[] = "hostperm.1";
@ -432,8 +432,12 @@ nsPermissionManager::Init()
rv = GetPrincipal(perm.host, perm.appId, perm.isInBrowserElement, getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
// The child process doesn't care about modification times - it neither
// reads nor writes, nor removes them based on the date - so 0 (which
// will end up as now()) is fine.
uint64_t modificationTime = 0;
AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
perm.expireTime, eNotify, eNoDBOperation);
perm.expireTime, modificationTime, eNotify, eNoDBOperation);
}
// Stop here; we don't need the DB in the child process
@ -546,6 +550,23 @@ nsPermissionManager::InitDB(bool aRemoveFile)
// fall through to the next upgrade
// Version 3->4 is the creation of the modificationTime field.
case 3:
{
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_hosts ADD modificationTime INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
// We leave the modificationTime at zero for all existing records; using
// now() would mean, eg, that doing "remove all from the last hour"
// within the first hour after migration would remove all permissions.
rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
}
// fall through to the next upgrade
// current version.
case HOSTS_SCHEMA_VERSION:
break;
@ -561,7 +582,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
// check if all the expected columns exist
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT host, type, permission, expireType, expireTime, appId, isInBrowserElement FROM moz_hosts"),
"SELECT host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement FROM moz_hosts"),
getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv))
break;
@ -583,8 +604,8 @@ nsPermissionManager::InitDB(bool aRemoveFile)
// cache frequently used statements (for insertion, deletion, and updating)
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_hosts "
"(id, host, type, permission, expireType, expireTime, appId, isInBrowserElement) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)"), getter_AddRefs(mStmtInsert));
"(id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"), getter_AddRefs(mStmtInsert));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
@ -594,7 +615,7 @@ nsPermissionManager::InitDB(bool aRemoveFile)
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"UPDATE moz_hosts "
"SET permission = ?2, expireType= ?3, expireTime = ?4 WHERE id = ?1"),
"SET permission = ?2, expireType= ?3, expireTime = ?4, modificationTime = ?5 WHERE id = ?1"),
getter_AddRefs(mStmtUpdate));
NS_ENSURE_SUCCESS(rv, rv);
@ -626,6 +647,7 @@ nsPermissionManager::CreateTable()
",permission INTEGER"
",expireType INTEGER"
",expireTime INTEGER"
",modificationTime INTEGER"
",appId INTEGER"
",isInBrowserElement INTEGER"
")"));
@ -679,8 +701,11 @@ nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal,
return NS_ERROR_INVALID_ARG;
}
// A modificationTime of zero will cause AddInternal to use now().
int64_t modificationTime = 0;
return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0,
aExpireType, aExpireTime, eNotify, eWriteToDB);
aExpireType, aExpireTime, modificationTime, eNotify, eWriteToDB);
}
nsresult
@ -690,6 +715,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
int64_t aID,
uint32_t aExpireType,
int64_t aExpireTime,
int64_t aModificationTime,
NotifyOperationType aNotifyOperation,
DBOperationType aDBOperation)
{
@ -760,15 +786,27 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
// even if the new permission is UNKNOWN_ACTION (which means a "logical
// remove" of the default)
op = eOperationReplacingDefault;
else if (aID == cIDPermissionIsDefault)
// We are adding a default permission but a "real" permission already
// exists. This almost-certainly means we just did a removeAllSince and
// are re-importing defaults - so we can ignore this.
op = eOperationNone;
else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
op = eOperationRemoving;
else
op = eOperationChanging;
}
// child processes should *always* be passed a modificationTime of zero.
MOZ_ASSERT(!IsChildProcess() || aModificationTime == 0);
// do the work for adding, deleting, or changing a permission:
// update the in-memory list, write to the db, and notify consumers.
int64_t id;
if (aModificationTime == 0) {
aModificationTime = PR_Now() / 1000;
}
switch (op) {
case eOperationNone:
{
@ -786,7 +824,9 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
id = aID;
}
entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission, aExpireType, aExpireTime));
entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission,
aExpireType, aExpireTime,
aModificationTime));
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION) {
uint32_t appId;
@ -797,7 +837,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
NS_ENSURE_SUCCESS(rv, rv);
UpdateDB(op, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, appId, isInBrowserElement);
UpdateDB(op, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, aModificationTime, appId, isInBrowserElement);
}
if (aNotifyOperation == eNotify) {
@ -824,7 +864,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
// We care only about the id here so we pass dummy values for all other
// parameters.
UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0,
nsIPermissionManager::EXPIRE_NEVER, 0, 0, false);
nsIPermissionManager::EXPIRE_NEVER, 0, 0, 0, false);
if (aNotifyOperation == eNotify) {
NotifyObserversWithPermission(host,
@ -866,12 +906,13 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
entry->GetPermissions()[index].mPermission = aPermission;
entry->GetPermissions()[index].mExpireType = aExpireType;
entry->GetPermissions()[index].mExpireTime = aExpireTime;
entry->GetPermissions()[index].mModificationTime = aModificationTime;
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
// We care only about the id, the permission and expireType/expireTime here.
// We care only about the id, the permission and expireType/expireTime/modificationTime here.
// We pass dummy values for all other parameters.
UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(),
aPermission, aExpireType, aExpireTime, 0, false);
aPermission, aExpireType, aExpireTime, aModificationTime, 0, false);
if (aNotifyOperation == eNotify) {
NotifyObserversWithPermission(host,
@ -915,6 +956,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
entry->GetPermissions()[index].mPermission = aPermission;
entry->GetPermissions()[index].mExpireType = aExpireType;
entry->GetPermissions()[index].mExpireTime = aExpireTime;
entry->GetPermissions()[index].mModificationTime = aModificationTime;
// If requested, create the entry in the DB.
if (aDBOperation == eWriteToDB) {
@ -926,7 +968,8 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
NS_ENSURE_SUCCESS(rv, rv);
UpdateDB(eOperationAdding, mStmtInsert, id, host, aType, aPermission, aExpireType, aExpireTime, appId, isInBrowserElement);
UpdateDB(eOperationAdding, mStmtInsert, id, host, aType, aPermission,
aExpireType, aExpireTime, aModificationTime, appId, isInBrowserElement);
}
if (aNotifyOperation == eNotify) {
@ -983,6 +1026,7 @@ nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal,
0,
nsIPermissionManager::EXPIRE_NEVER,
0,
0,
eNotify,
eWriteToDB);
}
@ -994,6 +1038,13 @@ nsPermissionManager::RemoveAll()
return RemoveAllInternal(true);
}
NS_IMETHODIMP
nsPermissionManager::RemoveAllSince(int64_t aSince)
{
ENSURE_NOT_CHILD_PROCESS;
return RemoveAllModifiedSince(aSince);
}
void
nsPermissionManager::CloseDB(bool aRebuildOnSuccess)
{
@ -1323,12 +1374,16 @@ nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
// helper struct for passing arguments into hash enumeration callback.
struct nsGetEnumeratorData
{
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray, const nsTArray<nsCString> *aTypes)
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray,
const nsTArray<nsCString> *aTypes,
int64_t aSince = 0)
: array(aArray)
, types(aTypes) {}
, types(aTypes)
, since(aSince) {}
nsCOMArray<nsIPermission> *array;
const nsTArray<nsCString> *types;
int64_t since;
};
static PLDHashOperator
@ -1395,6 +1450,76 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
return NS_OK;
}
static PLDHashOperator
AddPermissionsModifiedSinceToList(
nsPermissionManager::PermissionHashKey* entry, void* arg)
{
nsGetEnumeratorData* data = static_cast<nsGetEnumeratorData *>(arg);
for (size_t i = 0; i < entry->GetPermissions().Length(); ++i) {
const nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
if (data->since > permEntry.mModificationTime) {
continue;
}
nsPermission* perm = new nsPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
data->types->ElementAt(permEntry.mType),
permEntry.mPermission,
permEntry.mExpireType,
permEntry.mExpireTime);
data->array->AppendObject(perm);
}
return PL_DHASH_NEXT;
}
nsresult
nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
{
ENSURE_NOT_CHILD_PROCESS;
// roll an nsCOMArray of all our permissions, then hand out an enumerator
nsCOMArray<nsIPermission> array;
nsGetEnumeratorData data(&array, &mTypeArray, aModificationTime);
mPermissionTable.EnumerateEntries(AddPermissionsModifiedSinceToList, &data);
for (int32_t i = 0; i<array.Count(); ++i) {
nsAutoCString host;
bool isInBrowserElement = false;
nsAutoCString type;
uint32_t appId = 0;
array[i]->GetHost(host);
array[i]->GetIsInBrowserElement(&isInBrowserElement);
array[i]->GetType(type);
array[i]->GetAppId(&appId);
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetPrincipal(host, appId, isInBrowserElement,
getter_AddRefs(principal)))) {
NS_ERROR("GetPrincipal() failed!");
continue;
}
// AddInternal handles removal, so let it do the work...
AddInternal(
principal,
type,
nsIPermissionManager::UNKNOWN_ACTION,
0,
nsIPermissionManager::EXPIRE_NEVER, 0, 0,
nsPermissionManager::eNotify,
nsPermissionManager::eWriteToDB);
}
// now re-import any defaults as they may now be required if we just deleted
// an override.
ImportDefaults();
return NS_OK;
}
PLDHashOperator
nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
{
@ -1475,6 +1600,7 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
0,
nsIPermissionManager::EXPIRE_NEVER,
0,
0,
nsPermissionManager::eNotify,
nsPermissionManager::eNoDBOperation);
}
@ -1646,7 +1772,7 @@ nsPermissionManager::Read()
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, host, type, permission, expireType, expireTime, appId, isInBrowserElement "
"SELECT id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement "
"FROM moz_hosts"), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
@ -1655,6 +1781,7 @@ nsPermissionManager::Read()
uint32_t permission;
uint32_t expireType;
int64_t expireTime;
int64_t modificationTime;
uint32_t appId;
bool isInBrowserElement;
bool hasResult;
@ -1682,15 +1809,17 @@ nsPermissionManager::Read()
permission = stmt->AsInt32(3);
expireType = stmt->AsInt32(4);
// convert into int64_t value (milliseconds)
// convert into int64_t values (milliseconds)
expireTime = stmt->AsInt64(5);
modificationTime = stmt->AsInt64(6);
if (stmt->AsInt64(6) < 0) {
if (stmt->AsInt64(7) < 0) {
readError = true;
continue;
}
appId = static_cast<uint32_t>(stmt->AsInt64(6));
isInBrowserElement = static_cast<bool>(stmt->AsInt32(7));
appId = static_cast<uint32_t>(stmt->AsInt64(7));
isInBrowserElement = static_cast<bool>(stmt->AsInt32(8));
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = GetPrincipal(host, appId, isInBrowserElement, getter_AddRefs(principal));
@ -1700,7 +1829,7 @@ nsPermissionManager::Read()
}
rv = AddInternal(principal, type, permission, id, expireType, expireTime,
eDontNotify, eNoDBOperation);
modificationTime, eDontNotify, eNoDBOperation);
if (NS_FAILED(rv)) {
readError = true;
continue;
@ -1848,8 +1977,14 @@ nsPermissionManager::_DoImport(nsIInputStream *inputStream, mozIStorageConnectio
nsresult rv = GetPrincipal(lineArray[3], getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
// the import file format doesn't handle modification times, so we use
// 0, which AddInternal will convert to now()
int64_t modificationTime = 0;
rv = AddInternal(principal, lineArray[1], permission, id,
nsIPermissionManager::EXPIRE_NEVER, 0, eDontNotify, operation);
nsIPermissionManager::EXPIRE_NEVER, 0,
modificationTime,
eDontNotify, operation);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1880,6 +2015,7 @@ nsPermissionManager::UpdateDB(OperationType aOp,
uint32_t aPermission,
uint32_t aExpireType,
int64_t aExpireTime,
int64_t aModificationTime,
uint32_t aAppId,
bool aIsInBrowserElement)
{
@ -1912,10 +2048,13 @@ nsPermissionManager::UpdateDB(OperationType aOp,
rv = aStmt->BindInt64ByIndex(5, aExpireTime);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64ByIndex(6, aAppId);
rv = aStmt->BindInt64ByIndex(6, aModificationTime);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64ByIndex(7, aIsInBrowserElement);
rv = aStmt->BindInt64ByIndex(7, aAppId);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64ByIndex(8, aIsInBrowserElement);
break;
}
@ -1937,6 +2076,9 @@ nsPermissionManager::UpdateDB(OperationType aOp,
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64ByIndex(3, aExpireTime);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64ByIndex(4, aModificationTime);
break;
}

View File

@ -37,12 +37,14 @@ public:
{
public:
PermissionEntry(int64_t aID, uint32_t aType, uint32_t aPermission,
uint32_t aExpireType, int64_t aExpireTime)
uint32_t aExpireType, int64_t aExpireTime,
int64_t aModificationTime)
: mID(aID)
, mType(aType)
, mPermission(aPermission)
, mExpireType(aExpireType)
, mExpireTime(aExpireTime)
, mModificationTime(aModificationTime)
, mNonSessionPermission(aPermission)
, mNonSessionExpireType(aExpireType)
, mNonSessionExpireTime(aExpireTime)
@ -53,6 +55,7 @@ public:
uint32_t mPermission;
uint32_t mExpireType;
int64_t mExpireTime;
int64_t mModificationTime;
uint32_t mNonSessionPermission;
uint32_t mNonSessionExpireType;
uint32_t mNonSessionExpireTime;
@ -154,7 +157,7 @@ public:
// unknown permission... return relevant data
return PermissionEntry(-1, aType, nsIPermissionManager::UNKNOWN_ACTION,
nsIPermissionManager::EXPIRE_NEVER, 0);
nsIPermissionManager::EXPIRE_NEVER, 0, 0);
}
private:
@ -200,6 +203,7 @@ public:
int64_t aID,
uint32_t aExpireType,
int64_t aExpireTime,
int64_t aModificationTime,
NotifyOperationType aNotifyOperation,
DBOperationType aDBOperation);
@ -260,6 +264,7 @@ private:
uint32_t aPermission,
uint32_t aExpireType,
int64_t aExpireTime,
int64_t aModificationTime,
uint32_t aAppId,
bool aIsInBrowserElement);
@ -299,6 +304,13 @@ private:
RemoveExpiredPermissionsForAppEnumerator(PermissionHashKey* entry,
void* nonused);
/**
* This method removes all permissions modified after the specified time.
*/
nsresult
RemoveAllModifiedSince(int64_t aModificationTime);
nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<nsIIDNService> mIDNService;

View File

@ -3,8 +3,15 @@
// The origin we use in most of the tests.
const TEST_ORIGIN = "example.org";
const TEST_ORIGIN_2 = "example.com";
const TEST_PERMISSION = "test-permission";
function promiseTimeout(delay) {
let deferred = Promise.defer();
do_timeout(delay, deferred.resolve);
return deferred.promise;
}
function run_test() {
run_next_test();
}
@ -28,6 +35,7 @@ add_task(function* do_test() {
conv.writeString("# this is a comment\n");
conv.writeString("\n"); // a blank line!
conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN + "\n");
conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN_2 + "\n");
ostream.close();
// Set the preference used by the permission manager so the file is read.
@ -92,6 +100,47 @@ add_task(function* do_test() {
do_check_eq(Ci.nsIPermissionManager.PROMPT_ACTION, findCapabilityViaEnum());
yield checkCapabilityViaDB(Ci.nsIPermissionManager.PROMPT_ACTION);
// --------------------------------------------------------------
// check default permissions and removeAllSince work as expected.
pm.removeAll(); // ensure only defaults are there.
let permURI2 = NetUtil.newURI("http://" + TEST_ORIGIN_2);
let principal2 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI2);
// default for both principals is allow.
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
// Add a default override for TEST_ORIGIN_2 - this one should *not* be
// restored in removeAllSince()
pm.addFromPrincipal(principal2, TEST_PERMISSION, Ci.nsIPermissionManager.DENY_ACTION);
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
yield promiseTimeout(20);
let since = Number(Date.now());
yield promiseTimeout(20);
// explicitly add a permission which overrides the default for the first
// principal - this one *should* be removed by removeAllSince.
pm.addFromPrincipal(principal, TEST_PERMISSION, Ci.nsIPermissionManager.DENY_ACTION);
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
// do a removeAllSince.
pm.removeAllSince(since);
// the default for the first principal should re-appear as we modified it
// later then |since|
do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
// but the permission for principal2 should remain as we added that before |since|.
do_check_eq(Ci.nsIPermissionManager.DENY_ACTION,
pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION));
// remove the temp file we created.
file.remove(false);
});

View File

@ -113,13 +113,25 @@ function run_test() {
);
}
let earliestNow = Number(Date.now());
// Initialize the permission manager service
var pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
let latestNow = Number(Date.now());
// The schema should still be 3. We want this test to be updated for each
// schema update.
do_check_eq(connection.schemaVersion, 3);
// The schema should be upgraded to 4, and a 'modificationTime' column should
// exist with all records having a value of 0.
do_check_eq(connection.schemaVersion, 4);
let select = connection.createStatement("SELECT modificationTime FROM moz_hosts")
let numMigrated = 0;
while (select.executeStep()) {
let thisModTime = select.getInt64(0);
do_check_true(thisModTime == 0, "new modifiedTime field is correct");
numMigrated += 1;
}
// check we found at least 1 record that was migrated.
do_check_true(numMigrated > 0, "we found at least 1 record that was migrated");
// This permission should always be there.
let principal = Cc["@mozilla.org/scriptsecuritymanager;1"]

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that removing permissions since a specified time behaves as expected.
let test_generator = do_run_test();
function run_test() {
do_test_pending();
test_generator.next();
}
function continue_test()
{
do_run_generator(test_generator);
}
function do_run_test() {
// Set up a profile.
let profile = do_get_profile();
let pm = Services.perms;
// to help with testing edge-cases, we will arrange for .removeAllSince to
// remove *all* permissions from one principal and one permission from another.
let permURI1 = NetUtil.newURI("http://example.com");
let principal1 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI1);
let permURI2 = NetUtil.newURI("http://example.org");
let principal2 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(permURI2);
// add a permission now - this isn't going to be removed.
pm.addFromPrincipal(principal1, "test/remove-since", 1);
// sleep briefly, then record the time - we'll remove all since then.
do_timeout(20, continue_test);
yield;
let since = Number(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...
do_timeout(20, continue_test);
yield;
// add another item - this second one should get nuked.
pm.addFromPrincipal(principal1, "test/remove-since-2", 1);
// add 2 items for the second principal - both will be removed.
pm.addFromPrincipal(principal2, "test/remove-since", 1);
pm.addFromPrincipal(principal2, "test/remove-since-2", 1);
// do the removal.
pm.removeAllSince(since);
// principal1 - the first one should remain.
do_check_eq(1, pm.testPermissionFromPrincipal(principal1, "test/remove-since"));
// but the second should have been removed.
do_check_eq(0, pm.testPermissionFromPrincipal(principal1, "test/remove-since-2"));
// principal2 - both should have been removed.
do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since"));
do_check_eq(0, pm.testPermissionFromPrincipal(principal2, "test/remove-since-2"));
do_finish_generator_test(test_generator);
}

View File

@ -23,6 +23,7 @@ support-files =
[test_permmanager_getPermissionObject.js]
[test_permmanager_notifications.js]
[test_permmanager_removeall.js]
[test_permmanager_removesince.js]
[test_permmanager_load_invalid_entries.js]
skip-if = debug == true
[test_permmanager_idn.js]

View File

@ -37,7 +37,7 @@ interface nsIDOMWindow;
interface nsIPermission;
interface nsISimpleEnumerator;
[scriptable, uuid(c9fec678-f194-43c9-96b0-7bd9dbdd6bb0)]
[scriptable, uuid(620d9b61-8997-4d13-aa64-ec03341dd75b)]
interface nsIPermissionManager : nsISupports
{
/**
@ -132,6 +132,11 @@ interface nsIPermissionManager : nsISupports
*/
void removeAll();
/**
* Clear all permission information added since the specified time.
*/
void removeAllSince(in int64_t since);
/**
* Test whether a website has permission to perform the given action.
* @param uri the uri to be tested

View File

@ -241,8 +241,12 @@ class Permissions(object):
rows = cursor.execute("PRAGMA table_info(moz_hosts)")
count = len(rows.fetchall())
# if the db contains 9 columns, we're using user_version 4
if count == 9:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0, 0)"
cursor.execute("PRAGMA user_version=4;")
# if the db contains 8 columns, we're using user_version 3
if count == 8:
elif count == 8:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)"
cursor.execute("PRAGMA user_version=3;")
else:

View File

@ -40,7 +40,18 @@ http://127.0.0.1:8888 privileged
cursor.execute("PRAGMA user_version=%d;" % version)
if version == 3:
if version == 4:
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
modificationTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)""")
elif version == 3:
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
@ -59,7 +70,7 @@ http://127.0.0.1:8888 privileged
expireType INTEGER,
expireTime INTEGER)""")
else:
raise Exception("version must be 2 or 3")
raise Exception("version must be 2, 3 or 4")
permDB.commit()
cursor.close()
@ -149,7 +160,7 @@ http://127.0.0.1:8888 privileged
self.assertEqual(len(entries), 3)
columns = 8 if version == 3 else 6
columns = 9 if version == 4 else (8 if version == 3 else 6)
self.assertEqual(len(entries[0]), columns)
for x in range(4, columns):
self.assertEqual(entries[0][x], 0)
@ -160,6 +171,8 @@ http://127.0.0.1:8888 privileged
def test_existing_permissions_db_v3(self):
self.verify_user_version(3)
def test_existing_permissions_db_v4(self):
self.verify_user_version(4)
if __name__ == '__main__':
unittest.main()