Bug 519263 - Session and time-based expiration for permissions in permissions manager. r=dwitte,

sr=mrbkap. First patch! Yay!!
This commit is contained in:
Sid Stamm 2009-10-16 14:01:04 -07:00
parent fb285fa757
commit fb4694efc4
11 changed files with 404 additions and 45 deletions

View File

@ -884,7 +884,9 @@ nsOperaCookieMigrator::AddCookieOverride(nsIPermissionManager* aManager)
rv = aManager->Add(uri, "cookie",
(mCurrHandlingInfo == 1 || mCurrHandlingInfo == 3)
? (PRUint32) nsIPermissionManager::ALLOW_ACTION
: (PRUint32) nsIPermissionManager::DENY_ACTION);
: (PRUint32) nsIPermissionManager::DENY_ACTION,
nsIPermissionManager::EXPIRE_NEVER,
0);
mCurrHandlingInfo = 0;

View File

@ -189,7 +189,8 @@ nsCookiePermission::SetAccess(nsIURI *aURI,
// the permission codes used by nsIPermissionManager.
// this is nice because it avoids conversion code.
//
return mPermMgr->Add(aURI, kPermissionType, aAccess);
return mPermMgr->Add(aURI, kPermissionType, aAccess,
nsIPermissionManager::EXPIRE_NEVER, 0);
}
NS_IMETHODIMP
@ -361,13 +362,16 @@ nsCookiePermission::CanSetCookie(nsIURI *aURI,
if (rememberDecision) {
switch (*aResult) {
case nsICookiePromptService::DENY_COOKIE:
mPermMgr->Add(aURI, kPermissionType, (PRUint32) nsIPermissionManager::DENY_ACTION);
mPermMgr->Add(aURI, kPermissionType, (PRUint32) nsIPermissionManager::DENY_ACTION,
nsIPermissionManager::EXPIRE_NEVER, 0);
break;
case nsICookiePromptService::ACCEPT_COOKIE:
mPermMgr->Add(aURI, kPermissionType, (PRUint32) nsIPermissionManager::ALLOW_ACTION);
mPermMgr->Add(aURI, kPermissionType, (PRUint32) nsIPermissionManager::ALLOW_ACTION,
nsIPermissionManager::EXPIRE_NEVER, 0);
break;
case nsICookiePromptService::ACCEPT_SESSION_COOKIE:
mPermMgr->Add(aURI, kPermissionType, nsICookiePermission::ACCESS_SESSION);
mPermMgr->Add(aURI, kPermissionType, nsICookiePermission::ACCESS_SESSION,
nsIPermissionManager::EXPIRE_NEVER, 0);
break;
default:
break;

View File

@ -43,10 +43,14 @@ NS_IMPL_ISUPPORTS1(nsPermission, nsIPermission)
nsPermission::nsPermission(const nsACString &aHost,
const nsACString &aType,
PRUint32 aCapability)
PRUint32 aCapability,
PRUint32 aExpireType,
PRInt64 aExpireTime)
: mHost(aHost)
, mType(aType)
, mCapability(aCapability)
, mExpireType(aExpireType)
, mExpireTime(aExpireTime)
{
}
@ -74,3 +78,17 @@ nsPermission::GetCapability(PRUint32 *aCapability)
*aCapability = mCapability;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::GetExpireType(PRUint32 *aExpireType)
{
*aExpireType = mExpireType;
return NS_OK;
}
NS_IMETHODIMP
nsPermission::GetExpireTime(PRInt64 *aExpireTime)
{
*aExpireTime = mExpireTime;
return NS_OK;
}

View File

@ -50,13 +50,20 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPERMISSION
nsPermission(const nsACString &aHost, const nsACString &aType, PRUint32 aCapability);
nsPermission(const nsACString &aHost,
const nsACString &aType,
PRUint32 aCapability,
PRUint32 aExpireType,
PRInt64 aExpireTime);
virtual ~nsPermission();
protected:
nsCString mHost;
nsCString mType;
PRUint32 mCapability;
PRUint32 mExpireType;
PRInt64 mExpireTime;
};
#endif // nsPermission_h__

View File

@ -95,7 +95,7 @@ nsHostEntry::nsHostEntry(const nsHostEntry& toCopy)
// nsPermissionManager Implementation
static const char kPermissionsFileName[] = "permissions.sqlite";
#define HOSTS_SCHEMA_VERSION 1
#define HOSTS_SCHEMA_VERSION 2
static const char kHostpermFileName[] = "hostperm.1";
@ -198,6 +198,24 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
// the upgrading code from the previous version to the new one.
// fall through to current version
case 1:
{
// previous non-expiry version of database. Upgrade it by adding the
// expiration columns
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_hosts ADD expireType INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_hosts ADD expireTime INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
}
// fall through to the next upgrade
// current version.
case HOSTS_SCHEMA_VERSION:
break;
@ -227,7 +245,8 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
// check if all the expected columns exist
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT host, type, permission FROM moz_hosts"), getter_AddRefs(stmt));
"SELECT host, type, permission, expireType, expireTime FROM moz_hosts"),
getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv))
break;
@ -248,8 +267,8 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
// cache frequently used statements (for insertion, deletion, and updating)
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_hosts "
"(id, host, type, permission) "
"VALUES (?1, ?2, ?3, ?4)"), getter_AddRefs(mStmtInsert));
"(id, host, type, permission, expireType, expireTime) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6)"), getter_AddRefs(mStmtInsert));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
@ -259,7 +278,8 @@ nsPermissionManager::InitDB(PRBool aRemoveFile)
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_hosts "
"SET permission = ?2 WHERE id = ?1"), getter_AddRefs(mStmtUpdate));
"SET permission = ?2, expireType= ?3, expireTime = ?4 WHERE id = ?1"),
getter_AddRefs(mStmtUpdate));
NS_ENSURE_SUCCESS(rv, rv);
// check whether to import or just read in the db
@ -284,24 +304,38 @@ nsPermissionManager::CreateTable()
",host TEXT"
",type TEXT"
",permission INTEGER"
",expireType INTEGER"
",expireTime INTEGER"
")"));
}
NS_IMETHODIMP
nsPermissionManager::Add(nsIURI *aURI,
const char *aType,
PRUint32 aPermission)
PRUint32 aPermission,
PRUint32 aExpireType,
PRInt64 aExpireTime)
{
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aType);
NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER ||
aExpireType == nsIPermissionManager::EXPIRE_TIME ||
aExpireType == nsIPermissionManager::EXPIRE_SESSION,
NS_ERROR_INVALID_ARG);
nsresult rv;
// Skip addition if the permission is already expired.
if (aExpireType == nsIPermissionManager::EXPIRE_TIME &&
aExpireTime < PR_Now() / 1000)
return NS_OK;
nsCAutoString host;
rv = GetHost(aURI, host);
NS_ENSURE_SUCCESS(rv, rv);
return AddInternal(host, nsDependentCString(aType), aPermission, 0, eNotify, eWriteToDB);
return AddInternal(host, nsDependentCString(aType), aPermission, 0,
aExpireType, aExpireTime, eNotify, eWriteToDB);
}
nsresult
@ -309,6 +343,8 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
const nsAFlatCString &aType,
PRUint32 aPermission,
PRInt64 aID,
PRUint32 aExpireType,
PRInt64 aExpireTime,
NotifyOperationType aNotifyOperation,
DBOperationType aDBOperation)
{
@ -335,7 +371,6 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
// figure out the transaction type, and get any existing permission value
OperationType op;
PRInt32 index = entry->GetPermissionIndex(typeIndex);
PRUint32 oldPermission;
if (index == -1) {
if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
op = eOperationNone;
@ -343,9 +378,17 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
op = eOperationAdding;
} else {
oldPermission = entry->GetPermissions()[index].mPermission;
nsPermissionEntry oldPermissionEntry = entry->GetPermissions()[index];
if (aPermission == oldPermission)
// remove the permission if the permission is UNKNOWN, update the
// permission if its value or expire type have changed OR if the time has
// changed and the expire type is time, otherwise, don't modify. There's
// no need to modify a permission that doesn't expire with time when the
// only thing changed is the expire time.
if (aPermission == oldPermissionEntry.mPermission &&
aExpireType == oldPermissionEntry.mExpireType &&
(aExpireType != nsIPermissionManager::EXPIRE_TIME ||
aExpireTime == oldPermissionEntry.mExpireTime))
op = eOperationNone;
else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
op = eOperationRemoving;
@ -373,15 +416,17 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
id = aID;
}
entry->GetPermissions().AppendElement(nsPermissionEntry(typeIndex, aPermission, id));
entry->GetPermissions().AppendElement(nsPermissionEntry(typeIndex, aPermission, id, aExpireType, aExpireTime));
if (aDBOperation == eWriteToDB)
UpdateDB(op, mStmtInsert, id, aHost, aType, aPermission);
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
UpdateDB(op, mStmtInsert, id, aHost, aType, aPermission, aExpireType, aExpireTime);
if (aNotifyOperation == eNotify) {
NotifyObserversWithPermission(aHost,
mTypeArray[typeIndex],
aPermission,
aExpireType,
aExpireTime,
NS_LITERAL_STRING("added").get());
}
@ -390,7 +435,8 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
case eOperationRemoving:
{
id = entry->GetPermissions()[index].mID;
nsPermissionEntry oldPermissionEntry = entry->GetPermissions()[index];
id = oldPermissionEntry.mID;
entry->GetPermissions().RemoveElementAt(index);
// If no more types are present, remove the entry
@ -398,12 +444,15 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
mHostTable.RawRemoveEntry(entry);
if (aDBOperation == eWriteToDB)
UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0);
UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0,
nsIPermissionManager::EXPIRE_NEVER, 0);
if (aNotifyOperation == eNotify) {
NotifyObserversWithPermission(aHost,
mTypeArray[typeIndex],
oldPermission,
oldPermissionEntry.mPermission,
oldPermissionEntry.mExpireType,
oldPermissionEntry.mExpireTime,
NS_LITERAL_STRING("deleted").get());
}
@ -415,13 +464,15 @@ nsPermissionManager::AddInternal(const nsAFlatCString &aHost,
id = entry->GetPermissions()[index].mID;
entry->GetPermissions()[index].mPermission = aPermission;
if (aDBOperation == eWriteToDB)
UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(), aPermission);
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(), aPermission, aExpireType, aExpireTime);
if (aNotifyOperation == eNotify) {
NotifyObserversWithPermission(aHost,
mTypeArray[typeIndex],
aPermission,
aExpireType,
aExpireTime,
NS_LITERAL_STRING("changed").get());
}
@ -443,6 +494,8 @@ nsPermissionManager::Remove(const nsACString &aHost,
nsDependentCString(aType),
nsIPermissionManager::UNKNOWN_ACTION,
0,
nsIPermissionManager::EXPIRE_NEVER,
0,
eNotify,
eWriteToDB);
}
@ -516,7 +569,7 @@ nsPermissionManager::CommonTestPermission(nsIURI *aURI,
nsHostEntry *entry = GetHostEntry(host, typeIndex, aExactHostMatch);
if (entry)
*aPermission = entry->GetPermission(typeIndex);
*aPermission = entry->GetPermission(typeIndex).mPermission;
return NS_OK;
}
@ -531,10 +584,18 @@ nsPermissionManager::GetHostEntry(const nsAFlatCString &aHost,
{
PRUint32 offset = 0;
nsHostEntry *entry;
PRInt64 now = PR_Now() / 1000;
do {
entry = mHostTable.GetEntry(aHost.get() + offset);
if (entry) {
if (entry->GetPermission(aType) != nsIPermissionManager::UNKNOWN_ACTION)
nsPermissionEntry permEntry = entry->GetPermission(aType);
// if the entry is expired, remove and keep looking for others.
if (permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME &&
permEntry.mExpireTime < now)
Remove(aHost, mTypeArray[aType].get());
else if (permEntry.mPermission != nsIPermissionManager::UNKNOWN_ACTION)
break;
// reset entry, to be able to return null on failure
@ -572,7 +633,9 @@ AddPermissionsToList(nsHostEntry *entry, void *arg)
nsPermission *perm = new nsPermission(entry->GetHost(),
data->types->ElementAt(permEntry.mType),
permEntry.mPermission);
permEntry.mPermission,
permEntry.mExpireType,
permEntry.mExpireTime);
data->array->AppendObject(perm);
}
@ -653,15 +716,18 @@ nsPermissionManager::GetTypeIndex(const char *aType,
return mTypeArray.Length() - 1;
}
// wrapper function for mangling (host,type,perm) triplet into an nsIPermission.
// wrapper function for mangling (host,type,perm,expireType,expireTime)
// set into an nsIPermission.
void
nsPermissionManager::NotifyObserversWithPermission(const nsACString &aHost,
const nsCString &aType,
PRUint32 aPermission,
PRUint32 aExpireType,
PRInt64 aExpireTime,
const PRUnichar *aData)
{
nsCOMPtr<nsIPermission> permission =
new nsPermission(aHost, aType, aPermission);
new nsPermission(aHost, aType, aPermission, aExpireType, aExpireTime);
if (permission)
NotifyObservers(permission, aData);
}
@ -687,15 +753,37 @@ nsPermissionManager::Read()
{
nsresult rv;
// delete expired permissions before we read in the db
{
// this deletion has its own scope so the write lock is released when done.
nsCOMPtr<mozIStorageStatement> stmtDeleteExpired;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"DELETE FROM moz_hosts WHERE expireType = ?1 AND expireTime < ?2"),
getter_AddRefs(stmtDeleteExpired));
NS_ENSURE_SUCCESS(rv, rv);
rv = stmtDeleteExpired->BindInt32Parameter(0, nsIPermissionManager::EXPIRE_TIME);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmtDeleteExpired->BindInt64Parameter(1, PR_Now() / 1000);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult;
rv = stmtDeleteExpired->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, host, type, permission "
"SELECT id, host, type, permission, expireType, expireTime "
"FROM moz_hosts"), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 id;
nsCAutoString host, type;
PRUint32 permission;
PRUint32 expireType;
PRInt64 expireTime;
PRBool hasResult;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
// explicitly set our entry id counter for use in AddInternal(),
@ -711,8 +799,13 @@ nsPermissionManager::Read()
NS_ENSURE_SUCCESS(rv, rv);
permission = stmt->AsInt32(3);
expireType = stmt->AsInt32(4);
rv = AddInternal(host, type, permission, id, eDontNotify, eNoDBOperation);
// convert into PRInt64 value (milliseconds)
expireTime = stmt->AsInt64(5);
rv = AddInternal(host, type, permission, id, expireType, expireTime,
eDontNotify, eNoDBOperation);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -779,7 +872,8 @@ nsPermissionManager::Import()
continue;
}
rv = AddInternal(lineArray[3], lineArray[1], permission, 0, eDontNotify, eWriteToDB);
rv = AddInternal(lineArray[3], lineArray[1], permission, 0,
nsIPermissionManager::EXPIRE_NEVER, 0, eDontNotify, eWriteToDB);
NS_ENSURE_SUCCESS(rv, rv);
}
}
@ -823,7 +917,9 @@ nsPermissionManager::UpdateDB(OperationType aOp,
PRInt64 aID,
const nsACString &aHost,
const nsACString &aType,
PRUint32 aPermission)
PRUint32 aPermission,
PRUint32 aExpireType,
PRInt64 aExpireTime)
{
nsresult rv;
@ -844,6 +940,12 @@ nsPermissionManager::UpdateDB(OperationType aOp,
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt32Parameter(3, aPermission);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt32Parameter(4, aExpireType);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64Parameter(5, aExpireTime);
break;
}
@ -859,6 +961,12 @@ nsPermissionManager::UpdateDB(OperationType aOp,
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt32Parameter(1, aPermission);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt32Parameter(2, aExpireType);
if (NS_FAILED(rv)) break;
rv = aStmt->BindInt64Parameter(3, aExpireTime);
break;
}

View File

@ -60,14 +60,19 @@ class mozIStorageStatement;
class nsPermissionEntry
{
public:
nsPermissionEntry(PRUint32 aType, PRUint32 aPermission, PRInt64 aID)
nsPermissionEntry(PRUint32 aType, PRUint32 aPermission, PRInt64 aID,
PRUint32 aExpireType, PRInt64 aExpireTime)
: mType(aType)
, mPermission(aPermission)
, mID(aID) {}
, mID(aID)
, mExpireType(aExpireType)
, mExpireTime(aExpireTime) {}
PRUint32 mType;
PRUint32 mPermission;
PRInt64 mID;
PRUint32 mExpireType;
PRInt64 mExpireTime;
};
class nsHostEntry : public PLDHashEntryHdr
@ -130,13 +135,16 @@ public:
return -1;
}
inline PRUint32 GetPermission(PRUint32 aType) const
inline nsPermissionEntry GetPermission(PRUint32 aType) const
{
for (PRUint32 i = 0; i < mPermissions.Length(); ++i)
if (mPermissions[i].mType == aType)
return mPermissions[i].mPermission;
return mPermissions[i];
return nsIPermissionManager::UNKNOWN_ACTION;
// unknown permission... return relevant data
nsPermissionEntry unk = nsPermissionEntry(aType, nsIPermissionManager::UNKNOWN_ACTION,
-1, nsIPermissionManager::EXPIRE_NEVER, 0);
return unk;
}
private:
@ -184,6 +192,8 @@ private:
const nsAFlatCString &aType,
PRUint32 aPermission,
PRInt64 aID,
PRUint32 aExpireType,
PRInt64 aExpireTime,
NotifyOperationType aNotifyOperation,
DBOperationType aDBOperation);
@ -206,6 +216,8 @@ private:
void NotifyObserversWithPermission(const nsACString &aHost,
const nsCString &aType,
PRUint32 aPermission,
PRUint32 aExpireType,
PRInt64 aExpireTime,
const PRUnichar *aData);
void NotifyObservers(nsIPermission *aPermission, const PRUnichar *aData);
nsresult RemoveAllInternal();
@ -217,7 +229,9 @@ private:
PRInt64 aID,
const nsACString &aHost,
const nsACString &aType,
PRUint32 aPermission);
PRUint32 aPermission,
PRUint32 aExpireType,
PRInt64 aExpireTime);
nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<nsIIDNService> mIDNService;

View File

@ -0,0 +1,54 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
// setup a profile directory
var dir = do_get_profile();
// initialize the permission manager service
var pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var permURI = ios.newURI("http://example.com", null, null);
function run_test() {
// add a permission with *now* expiration
pm.add(permURI, "test/expiration-perm-exp", 1, pm.EXPIRE_TIME, (new Date()).getTime());
// add a permission with future expiration (100 milliseconds)
pm.add(permURI, "test/expiration-perm-exp2", 1, pm.EXPIRE_TIME, (new Date()).getTime() + 100);
// add a permission with future expiration (10000 milliseconds)
pm.add(permURI, "test/expiration-perm-exp3", 1, pm.EXPIRE_TIME, (new Date()).getTime() + 10000);
// add a permission without expiration
pm.add(permURI, "test/expiration-perm-nexp", 1, pm.EXPIRE_NEVER, 0);
// check that the permission expired
do_check_eq(0, pm.testPermission(permURI, "test/expiration-perm-exp"));
// ... and that the others didn't
do_check_eq(1, pm.testPermission(permURI, "test/expiration-perm-exp3"));
do_check_eq(1, pm.testPermission(permURI, "test/expiration-perm-nexp"));
// ... and that the short-term one will
do_test_pending();
do_timeout(200, "verifyExpiration();");
// clean up
do_test_pending();
do_timeout(300, "end_test();");
}
function verifyExpiration() {
do_check_eq(0, pm.testPermission(permURI, "test/expiration-perm-exp2"));
do_test_finished();
}
function end_test() {
// clean up
pm.removeAll();
do_test_finished();
}

View File

@ -0,0 +1,122 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
// setup a profile directory
var dir = do_get_profile();
// initialize the permission manager service
var pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var permURI = ios.newURI("http://example.com", null, null);
var theTime = (new Date()).getTime();
var numadds = 0;
var numchanges = 0;
var numdeletes = 0;
var needsToClear = true;
// will listen for stuff.
var observer = {
QueryInterface:
function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIObserver))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
observe:
function(subject, topic, data) {
if (topic !== "perm-changed")
return;
// "deleted" means a permission was deleted. aPermission is the deleted permission.
// "added" means a permission was added. aPermission is the added permission.
// "changed" means a permission was altered. aPermission is the new permission.
// "cleared" means the entire permission list was cleared. aPermission is null.
if (data == "added") {
var perm = subject.QueryInterface(Ci.nsIPermission);
numadds++;
switch (numadds) {
case 1: /* first add */
do_check_eq(pm.EXPIRE_TIME, perm.expireType);
do_check_eq(theTime + 10000, perm.expireTime);
break;
case 2: /* second add (permission-notify) */
do_check_eq(pm.EXPIRE_NEVER, perm.expireType);
do_check_eq(pm.DENY_ACTION, perm.capability);
break;
default:
do_throw("too many add notifications posted.");
}
do_test_finished();
} else if (data == "changed") {
var perm = subject.QueryInterface(Ci.nsIPermission);
numchanges++;
switch (numchanges) {
case 1:
do_check_eq(pm.EXPIRE_TIME, perm.expireType);
do_check_eq(theTime + 20000, perm.expireTime);
break;
default:
do_throw("too many change notifications posted.");
}
do_test_finished();
} else if (data == "deleted") {
var perm = subject.QueryInterface(Ci.nsIPermission);
numdeletes++;
switch (numdeletes) {
case 1:
do_check_eq("test/permission-notify", perm.type);
break;
default:
do_throw("too many delete notifications posted.");
}
do_test_finished();
} else if (data == "cleared") {
// only clear once: at the end
do_check_true(needsToClear);
needsToClear = false;
do_test_finished();
} else {
dump("subject: " + subject + " data: " + data + "\n");
}
},
};
function run_test() {
var obs = Cc["@mozilla.org/observer-service;1"].getService()
.QueryInterface(Ci.nsIObserverService);
obs.addObserver(observer, "perm-changed", false);
// add a permission
do_test_pending(); // for 'add' notification
pm.add(permURI, "test/expiration-perm", pm.ALLOW_ACTION, pm.EXPIRE_TIME, theTime + 10000);
do_test_pending(); // for 'change' notification
pm.add(permURI, "test/expiration-perm", pm.ALLOW_ACTION, pm.EXPIRE_TIME, theTime + 20000);
do_test_pending(); // for 'add' notification
pm.add(permURI, "test/permission-notify", pm.DENY_ACTION);
do_test_pending(); // for 'deleted' notification
pm.remove(permURI.asciiHost, "test/permission-notify");
do_test_pending(); // for 'cleared' notification
pm.removeAll();
do_timeout(100, "cleanup();");
}
function cleanup() {
obs.removeObserver(observer, "perm-changed");
}

View File

@ -38,8 +38,7 @@
#include "nsISupports.idl"
[scriptable, uuid(28F16D80-157B-11d5-A542-0010A401EB10)]
[scriptable, uuid(5036f0f6-f77b-4168-9d57-a1c0dd66cf02)]
/**
* This interface defines a "permission" object,
* used to specify allowed/blocked objects from
@ -66,4 +65,17 @@ interface nsIPermission : nsISupports
* The permission (see nsIPermissionManager.idl for allowed values)
*/
readonly attribute PRUint32 capability;
/**
* The expiration type of the permission (session, time-based or none).
* Constants are EXPIRE_*, defined in nsIPermissionManager.
* @see nsIPermissionManager
*/
readonly attribute PRUint32 expireType;
/**
* The expiration time of the permission (milliseconds since Jan 1 1970
* 0:00:00).
*/
readonly attribute PRInt64 expireTime;
};

View File

@ -66,7 +66,7 @@
interface nsIURI;
interface nsIObserver;
[scriptable, uuid(00708302-684c-42d6-a5a3-995d51b1d17c)]
[scriptable, uuid(0b83f9d5-3f96-41b6-91aa-ff3a7e4880d7)]
interface nsIPermissionManager : nsISupports
{
/**
@ -80,6 +80,15 @@ interface nsIPermissionManager : nsISupports
const PRUint32 ALLOW_ACTION = 1;
const PRUint32 DENY_ACTION = 2;
/**
* Predefined expiration types for permissions. Permissions can be permanent
* (never expire), expire at the end of the session, or expire at a specified
* time.
*/
const PRUint32 EXPIRE_NEVER = 0;
const PRUint32 EXPIRE_SESSION = 1;
const PRUint32 EXPIRE_TIME = 2;
/**
* Add permission information for a given URI and permission type. This
* operation will cause the type string to be registered if it does not
@ -98,10 +107,18 @@ interface nsIPermissionManager : nsISupports
* NOTE: UNKNOWN_ACTION (0) is reserved to represent the
* default permission when no entry is found for a host, and
* should not be used by consumers to indicate otherwise.
* @param expiretype a constant defining whether this permission should
* never expire (EXPIRE_NEVER), expire at the end of the
* session (EXPIRE_SESSION), or expire at a specified time
* (EXPIRE_TIME).
* @param expiretime an integer representation of when this permission
* should be forgotten (milliseconds since Jan 1 1970 0:00:00).
*/
void add(in nsIURI uri,
in string type,
in PRUint32 permission);
in PRUint32 permission,
[optional] in PRUint32 expireType,
[optional] in PRInt64 expireTime);
/**
* Remove permission information for a given host string and permission type.

View File

@ -300,7 +300,8 @@ static void updatePermissions( const char* aPref,
rv = NS_NewURI(getter_AddRefs(uri), host);
if (NS_SUCCEEDED(rv))
{
aPermissionManager->Add( uri, XPI_PERMISSION, aPermission );
aPermissionManager->Add( uri, XPI_PERMISSION, aPermission,
nsIPermissionManager::EXPIRE_NEVER, 0 );
}
start = match+1;
} while ( match > 0 );