Backend changes to support popup blocking whitelists. No Mozilla UI yet but used by Phoenix. bug 174765 r=danm,sr=jag,a=brendan

This commit is contained in:
dveditz%netscape.com 2002-10-25 02:31:12 +00:00
parent 6e9b4885ca
commit 54a4cd8e0d
12 changed files with 92 additions and 208 deletions

View File

@ -143,10 +143,9 @@
#include "nsIBindingManager.h"
#include "nsIXBLService.h"
#ifdef MOZ_PHOENIX
// Used by phoenix to do popup whitelisting
// used for popup blocking, needs to be converted to something
// belonging to the back-end like nsIContentPolicy
#include "nsIPopupWindowManager.h"
#endif
static nsIEntropyCollector* gEntropyCollector = nsnull;
static PRInt32 gRefCnt = 0;
@ -2173,9 +2172,6 @@ GlobalWindowImpl::Alert(const nsAString& aString)
{
NS_ENSURE_STATE(mDocShell);
if (CheckForAbusePoint())
return NS_OK;
nsAutoString str;
str.Assign(aString);
@ -2208,9 +2204,6 @@ GlobalWindowImpl::Confirm(const nsAString& aString, PRBool* aReturn)
{
NS_ENSURE_STATE(mDocShell);
if (CheckForAbusePoint())
return NS_OK;
nsAutoString str;
*aReturn = PR_FALSE;
@ -2249,9 +2242,6 @@ GlobalWindowImpl::Prompt(const nsAString& aMessage,
{
NS_ENSURE_STATE(mDocShell);
if (CheckForAbusePoint())
return NS_OK;
aReturn.Truncate(); // XXX Null string!!!
nsresult rv = NS_OK;
@ -2821,30 +2811,21 @@ GlobalWindowImpl::DisableExternalCapture()
return NS_ERROR_FAILURE;
}
#ifdef MOZ_PHOENIX
static
PRBool IsPopupWhitelisted(nsIDOMDocument* aDoc)
PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
{
// Phoenix whitelists popups. Subvert Mozilla's blacklist implementation and
// use it as a whitelist instead. If/when Mozilla receives a patch to do
// popup whitelisting, the #ifdefs can be removed, and the right list/api can
// be used.
PRBool whiteListed = PR_FALSE;
PRBool blocked = PR_FALSE;
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
nsCOMPtr<nsIPopupWindowManager> pm(do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID));
if (pm) {
if (pm && doc) {
nsCOMPtr<nsIURI> uri;
if (doc)
doc->GetDocumentURL(getter_AddRefs(uri));
doc->GetDocumentURL(getter_AddRefs(uri));
// Allow really means it wasn't in our list. So in Phoenix, we
// assume DENY means it's in the whitelist. It's all backwards! Backwards, I say!
PRUint32 permission;
if (NS_SUCCEEDED(pm->TestPermission(uri, &permission)))
whiteListed = (permission == nsIPopupWindowManager::DENY_POPUP);
PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
pm->TestPermission(uri, &permission);
blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
}
return whiteListed;
return blocked;
}
static
@ -2863,7 +2844,6 @@ void FirePopupBlockedEvent(nsIDOMDocument* aDoc)
}
}
}
#endif
/*
* Examine the current document state to see if we're in a way that is
@ -2891,51 +2871,27 @@ GlobalWindowImpl::CheckForAbusePoint ()
return PR_FALSE;
if (!mIsDocumentLoaded || mRunningTimeout) {
PRBool blockOpenOnLoad = PR_FALSE;
prefs->GetBoolPref("dom.disable_open_during_load", &blockOpenOnLoad);
if (blockOpenOnLoad) {
#ifdef DEBUG
printf ("*** Scripts executed during (un)load or as a result of "
"setTimeout() are potential javascript abuse points.\n");
#endif
PRBool blocked = IsPopupBlocked(mDocument);
if (blocked)
FirePopupBlockedEvent(mDocument);
return blocked;
}
#ifdef MOZ_PHOENIX
// see the definition of the function for details.
PRBool whitelisted = IsPopupWhitelisted(mDocument);
if (!whitelisted)
PRInt32 clickDelay = 0;
prefs->GetIntPref("dom.disable_open_click_delay", &clickDelay);
if (clickDelay) {
PRTime now, ll_delta;
PRInt32 delta;
now = PR_Now();
LL_SUB(ll_delta, now, mLastMouseButtonAction);
LL_L2I(delta, ll_delta);
delta /= 1000;
if (delta > clickDelay)
{
PRBool blocked = IsPopupBlocked(mDocument);
if (blocked)
FirePopupBlockedEvent(mDocument);
return !whitelisted;
#else
return PR_TRUE;
#endif
}
} else {
PRInt32 clickDelay = 0;
prefs->GetIntPref("dom.disable_open_click_delay", &clickDelay);
if (clickDelay) {
PRTime now, ll_delta;
PRInt32 delta;
now = PR_Now();
LL_SUB(ll_delta, now, mLastMouseButtonAction);
LL_L2I(delta, ll_delta);
delta /= 1000;
if (delta > clickDelay)
{
#ifdef DEBUG
printf ("*** Scripts executed more than %ims after a mouse button "
"action are potential javascript abuse points (%i.)\n",
clickDelay, delta);
#endif
#ifdef MOZ_PHOENIX
PRBool whitelisted = IsPopupWhitelisted(mDocument);
if (!whitelisted)
FirePopupBlockedEvent(mDocument);
return !whitelisted;
#else
return PR_TRUE;
#endif
}
return blocked;
}
}

View File

@ -76,6 +76,8 @@ extern PRBool Permission_Check
PRBool warningPref, cookie_CookieStruct * cookie_s, const char * message_string, int count_for_message);
extern nsresult Permission_AddHost
(const nsAFlatCString &host, PRBool permission, PRInt32 type, PRBool save);
extern nsresult permission_CheckFromList
(const char* hostname, PRBool &permission, PRInt32 type);
//extern void Permission_Free(PRInt32 hostNumber, PRInt32 type, PRBool save);
extern void Permission_Save(PRBool notify);

View File

@ -45,7 +45,6 @@
#include "nsIPrefBranch.h"
#include "nsIPrefBranchInternal.h"
#include "nsIPrefService.h"
#include "nsIPermissionManager.h"
#include "nsIServiceManagerUtils.h"
#include "nsIURI.h"
@ -53,12 +52,8 @@
The Popup Window Manager maintains popup window permissions by website.
*/
#define POLICYSTRING "policy"
#define CUSTOMSTRING "usecustom"
static const char sPopupPrefRoot[] = "privacy.popups.";
static const char sPopupPrefPolicyLeaf[] = POLICYSTRING;
static const char sPopupPrefCustomLeaf[] = CUSTOMSTRING;
#define POPUP_PREF "dom.disable_open_during_load"
static const char sPopupDisablePref[] = POPUP_PREF;
static const char sPermissionChangeNotification[] = PPM_CHANGE_NOTIFICATION;
static const char sXPCOMShutdownTopic[] = NS_XPCOM_SHUTDOWN_OBSERVER_ID;
static const char sPrefChangedTopic[] = NS_PREFBRANCH_PREFCHANGE_TOPIC_ID;
@ -68,8 +63,7 @@ static const char sPrefChangedTopic[] = NS_PREFBRANCH_PREFCHANGE_TOPIC_ID;
//*****************************************************************************
nsPopupWindowManager::nsPopupWindowManager() :
mPolicy(ALLOW_POPUP),
mCustomPermissions(PR_FALSE)
mPolicy(ALLOW_POPUP)
{
NS_INIT_ISUPPORTS();
}
@ -87,17 +81,14 @@ nsresult
nsPopupWindowManager::Init()
{
mOS = do_GetService("@mozilla.org/observer-service;1");
mPermManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs)
prefs->GetBranch(sPopupPrefRoot, getter_AddRefs(mPopupPrefBranch));
prefs->GetBranch("", getter_AddRefs(mPopupPrefBranch));
if (mOS && mPermManager && mPopupPrefBranch) {
if (mOS && mPopupPrefBranch) {
// initialize our local copy of the pref
Observe(NS_STATIC_CAST(nsIPopupWindowManager *, this),
sPrefChangedTopic, NS_LITERAL_STRING(POLICYSTRING).get());
Observe(NS_STATIC_CAST(nsIPopupWindowManager *, this),
sPrefChangedTopic, NS_LITERAL_STRING(CUSTOMSTRING).get());
sPrefChangedTopic, NS_LITERAL_STRING(POPUP_PREF).get());
return ObserveThings();
}
return NS_ERROR_FAILURE;
@ -110,29 +101,29 @@ nsPopupWindowManager::Init()
NS_IMETHODIMP
nsPopupWindowManager::GetDefaultPermission(PRUint32 *aDefaultPermission)
{
return ALLOW_POPUP;
NS_ENSURE_ARG_POINTER(aDefaultPermission);
*aDefaultPermission = mPolicy;
return NS_OK;
}
NS_IMETHODIMP
nsPopupWindowManager::SetDefaultPermission(PRUint32 aDefaultPermission)
{
NS_ASSERTION(aDefaultPermission == ALLOW_POPUP, "whitelist not supported");
return aDefaultPermission == ALLOW_POPUP ? NS_OK : NS_ERROR_FAILURE;
mPolicy = (aDefaultPermission == DENY_POPUP) ? DENY_POPUP : ALLOW_POPUP;
return NS_OK;
}
/* Note: since we don't support whitelists, Add(uri, true) is the same thing
as Remove(uri). However Add(uri, true) is not considered an error
because the method is used that way. */
NS_IMETHODIMP
nsPopupWindowManager::Add(nsIURI *aURI, PRBool aPermit)
{
NS_ENSURE_ARG_POINTER(aURI);
if (!mPermManager)
return NS_ERROR_UNEXPECTED;
nsCAutoString uri;
aURI->GetPrePath(uri);
if (NS_SUCCEEDED(mPermManager->Add(uri, aPermit, WINDOWPERMISSION)))
aURI->GetHostPort(uri);
if (uri.IsEmpty())
return NS_ERROR_FAILURE;
if (NS_SUCCEEDED(Permission_AddHost(uri, aPermit, WINDOWPERMISSION, PR_TRUE)))
return NotifyObservers(aURI);
return NS_ERROR_FAILURE;
}
@ -141,14 +132,14 @@ NS_IMETHODIMP
nsPopupWindowManager::Remove(nsIURI *aURI)
{
NS_ENSURE_ARG_POINTER(aURI);
if (!mPermManager)
return NS_ERROR_UNEXPECTED;
nsCAutoString uri;
aURI->GetPrePath(uri);
if (NS_SUCCEEDED(mPermManager->Add(uri, PR_TRUE, WINDOWPERMISSION)))
return NotifyObservers(aURI);
return NS_ERROR_FAILURE;
aURI->GetHostPort(uri);
if (uri.IsEmpty())
return NS_ERROR_FAILURE;
PERMISSION_Remove(uri, WINDOWPERMISSION);
return NotifyObservers(aURI);
}
NS_IMETHODIMP
@ -180,22 +171,28 @@ nsPopupWindowManager::TestPermission(nsIURI *aURI, PRUint32 *_retval)
*_retval = mPolicy;
if (mPolicy == ALLOW_POPUP && mCustomPermissions) {
if (mPermManager) {
/* Because of a bug/quirk/something in the PermissionManager
the value of blockDomain will be left unchanged if the URI
has no host port (like a local file URI, for instance).
And the PermissionManager will refuse to save permissions
for such URIs. A default of "false," then, allows local files
to show popup windows, and this can't be stopped. ("true"
would do just the opposite.) */
PRBool blockDomain = PR_FALSE; // default to not blocked
nsCAutoString uri;
aURI->GetPrePath(uri);
mPermManager->TestForBlocking(uri, WINDOWPERMISSION, &blockDomain);
*_retval = blockDomain ? DENY_POPUP : ALLOW_POPUP_WITH_PREJUDICE;
nsCAutoString uri;
aURI->GetHostPort(uri);
if (uri.IsEmpty())
return NS_OK;
/* Look for the specific host, if not found check its domains */
nsresult rv;
PRBool permission;
PRInt32 offset = 0;
const char* host = uri.get();
do {
rv = permission_CheckFromList(host+offset, permission, WINDOWPERMISSION);
if (NS_SUCCEEDED(rv)) {
/* found a value for the host/domain */
*_retval = permission ? ALLOW_POPUP : DENY_POPUP;
break;
}
}
/* try the parent domain */
offset = uri.FindChar('.', offset) + 1;
} while (offset > 0 );
return NS_OK;
}
@ -232,19 +229,14 @@ nsPopupWindowManager::Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *aData)
{
if (nsCRT::strcmp(aTopic, sPrefChangedTopic) == 0 &&
(NS_LITERAL_STRING(POLICYSTRING).Equals(aData) ||
NS_LITERAL_STRING(CUSTOMSTRING).Equals(aData))) {
// refresh our local copy of the "allow popups" pref
PRInt32 perm = ALLOW_POPUP;
PRBool custom = PR_FALSE;
NS_LITERAL_STRING(POPUP_PREF).Equals(aData)) {
// refresh our local copy of the "disable popups" pref
PRBool permission = PR_FALSE;
if (mPopupPrefBranch) {
mPopupPrefBranch->GetIntPref(sPopupPrefPolicyLeaf, &perm);
mPopupPrefBranch->GetBoolPref(sPopupPrefCustomLeaf, &custom);
NS_ASSERTION(perm >= 0, "popup pref value out of range");
mPopupPrefBranch->GetBoolPref(sPopupDisablePref, &permission);
}
mPolicy = NS_STATIC_CAST(PRUint32, perm);
mCustomPermissions = custom;
mPolicy = permission ? DENY_POPUP : ALLOW_POPUP;
} else if (nsCRT::strcmp(aTopic, sXPCOMShutdownTopic) == 0) {
// unhook cyclical references
StopObservingThings();
@ -270,8 +262,7 @@ nsPopupWindowManager::ObserveThings()
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIPrefBranchInternal> ibranch(do_QueryInterface(mPopupPrefBranch));
if (ibranch) {
ibranch->AddObserver(sPopupPrefPolicyLeaf, this, PR_FALSE);
rv = ibranch->AddObserver(sPopupPrefCustomLeaf, this, PR_FALSE);
ibranch->AddObserver(sPopupDisablePref, this, PR_FALSE);
}
}
@ -284,8 +275,7 @@ nsPopupWindowManager::StopObservingThings()
{
nsCOMPtr<nsIPrefBranchInternal> ibranch(do_QueryInterface(mPopupPrefBranch));
if (ibranch) {
ibranch->RemoveObserver(sPopupPrefPolicyLeaf, this);
ibranch->RemoveObserver(sPopupPrefCustomLeaf, this);
ibranch->RemoveObserver(sPopupDisablePref, this);
}
if (mOS)
@ -312,7 +302,6 @@ void
nsPopupWindowManager::DeInitialize()
{
mOS = 0;
mPermManager = 0;
mPopupPrefBranch = 0;
}

View File

@ -42,7 +42,6 @@
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIPermissionManager.h"
#include "nsIPopupWindowManager.h"
#include "nsIPrefBranch.h"
@ -67,9 +66,7 @@ private:
void DeInitialize();
PRUint32 mPolicy;
PRBool mCustomPermissions;
nsCOMPtr<nsIObserverService> mOS;
nsCOMPtr<nsIPermissionManager> mPermManager;
nsCOMPtr<nsIPrefBranch> mPopupPrefBranch;
};

View File

@ -214,6 +214,7 @@
oncommand="viewImages();"/>
</menupopup>
</menu>
<!--
<menu label="&cookiePopupManager.label;"
accesskey="&cookiePopupManager.accesskey;"
id="popup"
@ -233,5 +234,6 @@
oncommand="viewPopups();"/>
</menupopup>
</menu>
-->
</menupopup>
</overlay>

View File

@ -40,12 +40,14 @@
label="&images.label;"/>
</treerow>
</treeitem>
<!--
<treeitem position="3">
<treerow>
<treecell url="chrome://cookie/content/pref-popups.xul"
label="&popups.label;"/>
</treerow>
</treeitem>
-->
</treechildren>
</overlay>

View File

@ -66,30 +66,18 @@
#include "nsCOMPtr.h"
#include "nsAppShellCIDs.h"
#include "nsNetUtil.h"
#include "nsString.h"
#include "nsWidgetsCID.h"
#include "nsWindowCreator.h"
#include "nsIAppShell.h"
#include "nsIAppShellService.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDOMLocation.h"
#include "nsIDOMWindowInternal.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIJSContextStack.h"
#include "nsIPopupWindowManager.h"
#include "nsIPref.h"
#include "nsIServiceManager.h"
#include "nsIURI.h"
#include "nsIXULWindow.h"
#include "nsIWebBrowserChrome.h"
static NS_DEFINE_CID(kAppShellServiceCID, NS_APPSHELL_SERVICE_CID);
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
nsWindowCreator::nsWindowCreator() {
NS_INIT_ISUPPORTS();
@ -117,22 +105,9 @@ nsWindowCreator::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
NS_ENSURE_ARG_POINTER(_retval);
*_retval = 0;
PRUint32 allow = nsIPopupWindowManager::ALLOW_POPUP;
nsCOMPtr<nsIURI> parentURI;
GetParentURI(aParent, getter_AddRefs(parentURI));
if (aContextFlags & PARENT_IS_LOADING_OR_RUNNING_TIMEOUT)
allow = AllowWindowCreation(parentURI);
nsCOMPtr<nsIXULWindow> newWindow;
if (aParent) {
if (allow == nsIPopupWindowManager::DENY_POPUP)
return NS_OK; // ruse to not give scripts a catchable error
if (allow == nsIPopupWindowManager::ALLOW_POPUP &&
(aContextFlags & PARENT_IS_LOADING_OR_RUNNING_TIMEOUT))
aContextFlags &= ~PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
nsCOMPtr<nsIXULWindow> xulParent(do_GetInterface(aParent));
NS_ASSERTION(xulParent, "window created using non-XUL parent. that's unexpected, but may work.");
@ -166,45 +141,3 @@ nsWindowCreator::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
return *_retval ? NS_OK : NS_ERROR_FAILURE;
}
PRUint32
nsWindowCreator::AllowWindowCreation(nsIURI *aURI)
{
#ifdef MOZ_PHOENIX
// Phoenix doesn't check here. It checks over in nsGlobalWindow.cpp.
return nsIPopupWindowManager::ALLOW_POPUP;
#else
nsCOMPtr<nsIPopupWindowManager> pm(do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID));
if (!pm)
return nsIPopupWindowManager::ALLOW_POPUP;
PRUint32 permission;
if (NS_SUCCEEDED(pm->TestPermission(aURI, &permission)))
return permission;
return nsIPopupWindowManager::ALLOW_POPUP;
#endif
}
void
nsWindowCreator::GetParentURI(nsIWebBrowserChrome *aParent, nsIURI **aURI)
{
if (!aParent)
return;
nsCOMPtr<nsIDocShellTreeOwner> treeOwner(do_GetInterface(aParent));
if (treeOwner) {
nsCOMPtr<nsIDocShellTreeItem> content;
treeOwner->GetPrimaryContentShell(getter_AddRefs(content));
nsCOMPtr<nsIDOMWindowInternal> domParent(do_GetInterface(content));
if (domParent) {
nsCOMPtr<nsIDOMLocation> location;
domParent->GetLocation(getter_AddRefs(location));
if (location) {
nsAutoString url;
location->GetHref(url);
NS_NewURI(aURI, url);
}
}
}
}

View File

@ -52,10 +52,6 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWINDOWCREATOR
NS_DECL_NSIWINDOWCREATOR2
private:
PRUint32 AllowWindowCreation(nsIURI *aURI);
void GetParentURI(nsIWebBrowserChrome *aParent, nsIURI **aURI);
};
#endif

View File

@ -418,6 +418,7 @@ nsContextMenu.prototype = {
}
},
initPopupURL: function() {
return; // remove this line to reenable the context menu
// quick check: if no opener, it can't be a popup
if (!window.content.opener)
return;

View File

@ -214,6 +214,7 @@
oncommand="viewImages();"/>
</menupopup>
</menu>
<!--
<menu label="&cookiePopupManager.label;"
accesskey="&cookiePopupManager.accesskey;"
id="popup"
@ -233,5 +234,6 @@
oncommand="viewPopups();"/>
</menupopup>
</menu>
-->
</menupopup>
</overlay>

View File

@ -40,12 +40,14 @@
label="&images.label;"/>
</treerow>
</treeitem>
<!--
<treeitem position="3">
<treerow>
<treecell url="chrome://cookie/content/pref-popups.xul"
label="&popups.label;"/>
</treerow>
</treeitem>
-->
</treechildren>
</overlay>

View File

@ -40,12 +40,14 @@
label="&images.label;"/>
</treerow>
</treeitem>
<!--
<treeitem position="3">
<treerow>
<treecell url="chrome://cookie/content/pref-popups.xul"
label="&popups.label;"/>
</treerow>
</treeitem>
-->
</treechildren>
</overlay>