Bug 811026 - [Permissions] Grant a prompted permission for the duration of the session, r=sicking

This commit is contained in:
Andrea Marchesini 2013-01-05 14:02:29 -08:00
parent a9fccc4e48
commit 1a0052f653
6 changed files with 236 additions and 15 deletions

View File

@ -35,7 +35,7 @@ XPCOMUtils.defineLazyServiceGetter(this,
"@mozilla.org/permissionSettings;1",
"nsIDOMPermissionSettings");
function rememberPermission(aPermission, aPrincipal)
function rememberPermission(aPermission, aPrincipal, aSession)
{
function convertPermToAllow(aPerm, aPrincipal)
{
@ -44,9 +44,16 @@ function rememberPermission(aPermission, aPrincipal)
if (type == Ci.nsIPermissionManager.PROMPT_ACTION ||
(type == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION);
if (!aSession) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION);
} else {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
}
}
}
@ -102,10 +109,7 @@ ContentPermissionPrompt.prototype = {
evt.target.removeEventListener(evt.type, contentEvent);
if (evt.detail.type == "permission-allow") {
if (evt.detail.remember) {
rememberPermission(request.type, request.principal);
}
rememberPermission(request.type, request.principal, !evt.detail.remember);
request.allow();
return;
}
@ -113,6 +117,10 @@ ContentPermissionPrompt.prototype = {
if (evt.detail.remember) {
Services.perms.addFromPrincipal(request.principal, access,
Ci.nsIPermissionManager.DENY_ACTION);
} else {
Services.perms.addFromPrincipal(request.principal, access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
}
request.cancel();

View File

@ -57,6 +57,7 @@
#include "nsIEditor.h"
#include "nsIEditorDocShell.h"
#include "nsIMozBrowserFrame.h"
#include "nsIPermissionManager.h"
#include "nsLayoutUtils.h"
#include "nsView.h"
@ -282,6 +283,7 @@ NS_INTERFACE_MAP_END
nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
: mOwnerContent(aOwner)
, mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
, mDetachedSubdocViews(nullptr)
, mDepthTooGreat(false)
, mIsTopLevelContent(false)
@ -303,6 +305,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mRenderMode(RENDER_MODE_DEFAULT)
, mEventMode(EVENT_MODE_NORMAL_DISPATCH)
{
ResetPermissionManagerStatus();
}
nsFrameLoader*
@ -1404,6 +1407,8 @@ nsFrameLoader::SetOwnerContent(Element* aContent)
if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
rfp->OwnerContentChanged(aContent);
}
ResetPermissionManagerStatus();
}
bool
@ -2541,3 +2546,59 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
is_targetable, value);
}
}
void
nsFrameLoader::ResetPermissionManagerStatus()
{
// Finding the new app Id:
// . first we check if the owner is an app frame
// . second, we check if the owner is a browser frame
// in both cases we populate the appId variable.
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
if (OwnerIsAppFrame()) {
// You can't be both an app and a browser frame.
MOZ_ASSERT(!OwnerIsBrowserFrame());
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
MOZ_ASSERT(ownApp);
uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) {
appId = ownAppId;
}
}
if (OwnerIsBrowserFrame()) {
// You can't be both a browser and an app frame.
MOZ_ASSERT(!OwnerIsAppFrame());
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) {
appId = containingAppId;
}
}
// Nothing changed.
if (appId == mAppIdSentToPermissionManager) {
return;
}
nsCOMPtr<nsIPermissionManager> permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!permMgr) {
NS_ERROR("No PermissionManager available!");
return;
}
// If previously we registered an appId, we have to unregister it.
if (mAppIdSentToPermissionManager != nsIScriptSecurityManager::NO_APP_ID) {
permMgr->ReleaseAppId(mAppIdSentToPermissionManager);
mAppIdSentToPermissionManager = nsIScriptSecurityManager::NO_APP_ID;
}
// Register the new AppId.
if (appId != nsIScriptSecurityManager::NO_APP_ID) {
mAppIdSentToPermissionManager = appId;
permMgr->AddrefAppId(mAppIdSentToPermissionManager);
}
}

View File

@ -381,10 +381,17 @@ private:
return mOwnerContent->IsXUL() ? nsGkAtoms::type : nsGkAtoms::mozframetype;
}
// Update the permission manager's app-id refcount based on mOwnerContent's
// own-or-containing-app.
void ResetPermissionManagerStatus();
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIURI> mURIToLoad;
mozilla::dom::Element* mOwnerContent; // WEAK
// Note: this variable must be modified only by ResetPermissionManagerStatus()
uint32_t mAppIdSentToPermissionManager;
public:
// public because a callback needs these.
nsRefPtr<nsFrameMessageManager> mMessageManager;

View File

@ -660,9 +660,9 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
// 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 &&
if (aPermission == oldPermissionEntry.mPermission &&
aExpireType == oldPermissionEntry.mExpireType &&
(aExpireType != nsIPermissionManager::EXPIRE_TIME ||
(aExpireType != nsIPermissionManager::EXPIRE_TIME ||
aExpireTime == oldPermissionEntry.mExpireTime))
op = eOperationNone;
else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
@ -753,6 +753,15 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
case eOperationChanging:
{
id = entry->GetPermissions()[index].mID;
// If the new expireType is EXPIRE_SESSION, then we have to keep a
// copy of the previous permission value. This cached value will be
// used when restoring the permissions of an app.
if (entry->GetPermissions()[index].mExpireType != nsIPermissionManager::EXPIRE_SESSION &&
aExpireType == nsIPermissionManager::EXPIRE_SESSION) {
entry->GetPermissions()[index].mNonSessionPermission = entry->GetPermissions()[index].mPermission;
}
entry->GetPermissions()[index].mPermission = aPermission;
if (aDBOperation == eWriteToDB && aExpireType != nsIPermissionManager::EXPIRE_SESSION)
@ -1204,6 +1213,64 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId)
return NS_OK;
}
PLDHashOperator
nsPermissionManager::RemoveExpiredPermissionsForAppEnumerator(
nsPermissionManager::PermissionHashKey* entry, void* arg)
{
uint32_t* appId = static_cast<uint32_t*>(arg);
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
if (entry->GetKey()->mAppId != *appId) {
continue;
}
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
if (permEntry.mExpireType == nsIPermissionManager::EXPIRE_SESSION) {
PermissionEntry oldPermissionEntry = entry->GetPermissions()[i];
entry->GetPermissions().RemoveElementAt(i);
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
gPermissionManager->mTypeArray.ElementAt(oldPermissionEntry.mType),
oldPermissionEntry.mPermission,
oldPermissionEntry.mExpireType,
oldPermissionEntry.mExpireTime,
NS_LITERAL_STRING("deleted").get());
--i;
continue;
}
if (permEntry.mNonSessionPermission != permEntry.mPermission) {
permEntry.mPermission = permEntry.mNonSessionPermission;
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
entry->GetKey()->mAppId,
entry->GetKey()->mIsInBrowserElement,
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
permEntry.mPermission,
permEntry.mExpireType,
permEntry.mExpireTime,
NS_LITERAL_STRING("changed").get());
}
}
return PL_DHASH_NEXT;
}
nsresult
nsPermissionManager::RemoveExpiredPermissionsForApp(uint32_t aAppId)
{
ENSURE_NOT_CHILD_PROCESS;
if (aAppId != nsIScriptSecurityManager::NO_APP_ID) {
mPermissionTable.EnumerateEntries(RemoveExpiredPermissionsForAppEnumerator, &aAppId);
}
return NS_OK;
}
//*****************************************************************************
//*** nsPermissionManager private methods
//*****************************************************************************
@ -1418,10 +1485,10 @@ nsPermissionManager::Import()
// Split the line at tabs
ParseString(buffer, '\t', lineArray);
if (lineArray[0].EqualsLiteral(kMatchTypeHost) &&
lineArray.Length() == 4) {
nsresult error;
uint32_t permission = lineArray[2].ToInteger(&error);
if (NS_FAILED(error))
@ -1491,7 +1558,7 @@ nsPermissionManager::UpdateDB(OperationType aOp,
rv = aStmt->BindUTF8StringByIndex(1, aHost);
if (NS_FAILED(rv)) break;
rv = aStmt->BindUTF8StringByIndex(2, aType);
if (NS_FAILED(rv)) break;
@ -1550,3 +1617,51 @@ nsPermissionManager::UpdateDB(OperationType aOp,
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
NS_IMETHODIMP
nsPermissionManager::AddrefAppId(uint32_t aAppId)
{
if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
return NS_OK;
}
bool found = false;
for (uint32_t i = 0; i < mAppIdRefcounts.Length(); ++i) {
if (mAppIdRefcounts[i].mAppId == aAppId) {
++mAppIdRefcounts[i].mCounter;
found = true;
break;
}
}
if (!found) {
ApplicationCounter app = { aAppId, 1 };
mAppIdRefcounts.AppendElement(app);
}
return NS_OK;
}
NS_IMETHODIMP
nsPermissionManager::ReleaseAppId(uint32_t aAppId)
{
// An app has been released, maybe we have to reset its session.
if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
return NS_OK;
}
for (uint32_t i = 0; i < mAppIdRefcounts.Length(); ++i) {
if (mAppIdRefcounts[i].mAppId == aAppId) {
--mAppIdRefcounts[i].mCounter;
if (!mAppIdRefcounts[i].mCounter) {
mAppIdRefcounts.RemoveElementAt(i);
return RemoveExpiredPermissionsForApp(aAppId);
}
break;
}
}
return NS_OK;
}

View File

@ -19,6 +19,7 @@
#include "nsHashKeys.h"
#include "nsAutoPtr.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
class nsIPermission;
class nsIIDNService;
@ -42,6 +43,7 @@ public:
, mPermission(aPermission)
, mExpireType(aExpireType)
, mExpireTime(aExpireTime)
, mNonSessionPermission(aPermission)
{}
int64_t mID;
@ -49,6 +51,7 @@ public:
uint32_t mPermission;
uint32_t mExpireType;
int64_t mExpireTime;
uint32_t mNonSessionPermission;
};
/**
@ -246,6 +249,8 @@ private:
uint32_t aAppId,
bool aIsInBrowserElement);
nsresult RemoveExpiredPermissionsForApp(uint32_t aAppId);
/**
* This struct has to be passed as an argument to GetPermissionsForApp.
* |appId| has to be defined.
@ -266,7 +271,15 @@ private:
* specific app.
* @param arg has to be an instance of GetPermissionsForAppStruct.
*/
static PLDHashOperator GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg);
static PLDHashOperator
GetPermissionsForApp(PermissionHashKey* entry, void* arg);
/**
* This method restores an app's permissions when its session ends.
*/
static PLDHashOperator
RemoveExpiredPermissionsForAppEnumerator(PermissionHashKey* entry,
void* nonused);
nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<nsIIDNService> mIDNService;
@ -283,6 +296,13 @@ private:
// An array to store the strings identifying the different types.
nsTArray<nsCString> mTypeArray;
// A list of struct for counting applications
struct ApplicationCounter {
uint32_t mAppId;
uint32_t mCounter;
};
nsTArray<ApplicationCounter> mAppIdRefcounts;
// Initially, |false|. Set to |true| once shutdown has started, to avoid
// reopening the database.
bool mIsShuttingDown;

View File

@ -36,7 +36,7 @@ interface nsIObserver;
interface nsIPrincipal;
interface nsIDOMWindow;
[scriptable, uuid(ad79e135-6904-4734-8137-a511016d2723)]
[scriptable, uuid(6c68cd87-4569-4695-8bc8-ad609f624b96)]
interface nsIPermissionManager : nsISupports
{
/**
@ -173,6 +173,16 @@ interface nsIPermissionManager : nsISupports
uint32_t testExactPermissionFromPrincipal(in nsIPrincipal principal,
in string type);
/**
* Increment or decrement our "refcount" of an app id.
*
* We use this refcount to determine an app's lifetime. When an app's
* refcount goes to 0, we clear the permissions given to the app which are
* set to expire at the end of its session.
*/
void addrefAppId(in unsigned long appId);
void releaseAppId(in unsigned long appId);
/**
* Allows enumeration of all stored permissions
* @return an nsISimpleEnumerator interface that allows access to