Bug 105050 - return null window.opener to scripts if opener is a mail window.

Bug 32571 - Prompt user before allowing scripts to close windows if opener is null.
both r=heikki, sr=jst.
This commit is contained in:
mstoltz%netscape.com 2002-02-19 01:09:45 +00:00
Родитель ce1b14f952
Коммит 7446e86422
8 изменённых файлов: 140 добавлений и 10 удалений

Просмотреть файл

@ -198,6 +198,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
[noscript] nsIPrincipal getObjectPrincipal(in JSContextPtr cx, [noscript] nsIPrincipal getObjectPrincipal(in JSContextPtr cx,
in JSObjectPtr obj); in JSObjectPtr obj);
/**
* Returns true if the principal of the currently running script is the
* system principal, false otherwise.
*/
boolean subjectPrincipalIsSystem();
/** /**
* Forget all currently stored security policies and reread from prefs. * Forget all currently stored security policies and reread from prefs.
* This must be called after any capability.policy prefs have changed. * This must be called after any capability.policy prefs have changed.

Просмотреть файл

@ -1240,6 +1240,31 @@ nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem)
{
NS_ENSURE_ARG_POINTER(aIsSystem);
*aIsSystem = PR_FALSE;
if (!mSystemPrincipal)
return NS_OK;
nsCOMPtr<nsIPrincipal> subject;
nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
if (NS_FAILED(rv))
return rv;
if(!subject)
{
// No subject principal means no JS is running;
// this is the equivalent of system principal code
*aIsSystem = PR_TRUE;
return NS_OK;
}
return mSystemPrincipal->Equals(subject, aIsSystem);
}
NS_IMETHODIMP NS_IMETHODIMP
nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID, nsScriptSecurityManager::GetCertificatePrincipal(const char* aCertID,
nsIPrincipal **result) nsIPrincipal **result)
@ -2677,7 +2702,6 @@ nsScriptSecurityManager::InitPrefs()
PRUint32 prefCount; PRUint32 prefCount;
char** prefNames; char** prefNames;
//-- Set a callback for policy changes
// Registering the security manager as an observer to the // Registering the security manager as an observer to the
// profile-after-change topic. We will build up the policy table // profile-after-change topic. We will build up the policy table
// after the initial profile loads and after profile switches. // after the initial profile loads and after profile switches.

Просмотреть файл

@ -1 +1,4 @@
JSURLLoadBlockedWarning=Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager. JSURLLoadBlockedWarning = Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager.
ConfirmWindowCloseDialogTitle = Close Window?
ConfirmWindowCloseDialogText = A script wants to close the current window. Do you wish to allow this?

Просмотреть файл

@ -60,6 +60,7 @@ REQUIRES = xpcom \
xmlextras \ xmlextras \
find \ find \
appshell \ appshell \
intl \
$(NULL) $(NULL)
CPPSRCS = \ CPPSRCS = \

Просмотреть файл

@ -57,6 +57,7 @@ REQUIRES = xpcom \
htmlparser \ htmlparser \
chardet \ chardet \
transformiix \ transformiix \
intl \
xmlextras \ xmlextras \
find \ find \
appshell \ appshell \

Просмотреть файл

@ -124,6 +124,7 @@
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "nsDOMClassInfo.h" #include "nsDOMClassInfo.h"
#include "nsIJSNativeInitializer.h" #include "nsIJSNativeInitializer.h"
#include "nsIStringBundle.h"
#include "plbase64.h" #include "plbase64.h"
@ -155,7 +156,7 @@ static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID); // For window.find() static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID); // For window.find()
static const char *sWindowWatcherContractID = "@mozilla.org/embedcomp/window-watcher;1"; static const char *sWindowWatcherContractID = "@mozilla.org/embedcomp/window-watcher;1";
static const char *sJSStackContractID = "@mozilla.org/js/xpc/ContextStack;1"; static const char *sJSStackContractID = "@mozilla.org/js/xpc/ContextStack;1";
static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
static const char * const kCryptoContractID = NS_CRYPTO_CONTRACTID; static const char * const kCryptoContractID = NS_CRYPTO_CONTRACTID;
static const char * const kPkcs11ContractID = NS_PKCS11_CONTRACTID; static const char * const kPkcs11ContractID = NS_PKCS11_CONTRACTID;
@ -1156,7 +1157,28 @@ GlobalWindowImpl::GetControllers(nsIControllers** aResult)
NS_IMETHODIMP NS_IMETHODIMP
GlobalWindowImpl::GetOpener(nsIDOMWindowInternal** aOpener) GlobalWindowImpl::GetOpener(nsIDOMWindowInternal** aOpener)
{ {
*aOpener = mOpener; *aOpener = nsnull;
// We don't want to reveal the opener if the opener is a mail window,
// because opener can be used to spoof the contents of a message (bug 105050).
// So, we look in the opener's root docshell to see if it's a mail window.
nsCOMPtr<nsIScriptGlobalObject> openerSGO(do_QueryInterface(mOpener));
if (openerSGO) {
nsCOMPtr<nsIDocShell> openerDocShell;
openerSGO->GetDocShell(getter_AddRefs(openerDocShell));
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(openerDocShell));
if (docShellAsItem) {
nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
if (openerRootDocShell) {
PRUint32 appType;
nsresult rv = openerRootDocShell->GetAppType(&appType);
if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
*aOpener = mOpener;
}
}
}
}
NS_IF_ADDREF(*aOpener); NS_IF_ADDREF(*aOpener);
return NS_OK; return NS_OK;
} }
@ -2438,6 +2460,46 @@ GlobalWindowImpl::GetFrames(nsIDOMWindow** aFrames)
return NS_OK; return NS_OK;
} }
#define DOM_PROPERTIES_URL "chrome://communicator/locale/dom/dom.properties"
nsresult
GlobalWindowImpl::ConfirmClose(PRBool* aConfirmed)
{
nsresult rv;
// Get the localized strings for the dialog
nsCOMPtr<nsIStringBundleService> bundleService(
do_GetService(kStringBundleServiceCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
//XXX: What to do on error?
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(NS_LITERAL_CSTRING(DOM_PROPERTIES_URL).get(),
getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLString confirmTitle;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("ConfirmWindowCloseDialogTitle").get(),
getter_Copies(confirmTitle));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLString confirmText;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("ConfirmWindowCloseDialogText").get(),
getter_Copies(confirmText));
NS_ENSURE_SUCCESS(rv, rv);
// Show the dialog
nsCOMPtr<nsIPrompt> prompter;
rv = GetPrompter(getter_AddRefs(prompter));
NS_ENSURE_SUCCESS(rv, rv);
return prompter->Confirm(confirmTitle,
confirmText, aConfirmed);
}
#define DENY_SCRIPT_CLOSE 0
#define CONFIRM_SCRIPT_CLOSE 1
#define ALLOW_SCRIPT_CLOSE 2
NS_IMETHODIMP NS_IMETHODIMP
GlobalWindowImpl::Close() GlobalWindowImpl::Close()
{ {
@ -2447,15 +2509,44 @@ GlobalWindowImpl::Close()
if (parent != NS_STATIC_CAST(nsIDOMWindow *, this)) { if (parent != NS_STATIC_CAST(nsIDOMWindow *, this)) {
// window.close() is called on a frame in a frameset, such calls // window.close() is called on a frame in a frameset, such calls
// are ignored. // are ignored.
return NS_OK; return NS_OK;
} }
// Note: the basic security check, rejecting windows not opened through JS, // If this window was not opened by script (!mOpener), find out
// has been removed. This was approved long ago by ...you're going to call me // whether it's OK for a script to close it.
// on this, aren't you... well it was. And anyway, a better means is coming. if (!mOpener) {
// In the new world of application-level interfaces being written in JS, this nsresult rv;
// security check was causing problems. nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// System scripts can close all windows
PRBool InSystemCode = PR_FALSE;
rv = secMan->SubjectPrincipalIsSystem(&InSystemCode);
if (NS_FAILED(rv) || !InSystemCode) {
// Check the pref "dom.allow_scripts_to_close_windows"
nsCOMPtr<nsIPref> pref(do_GetService(kPrefServiceCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 closePref;
rv = pref->GetIntPref("dom.allow_scripts_to_close_windows", &closePref);
if (NS_FAILED(rv))
closePref = CONFIRM_SCRIPT_CLOSE;
PRBool confirmOK = PR_FALSE;
if (closePref == CONFIRM_SCRIPT_CLOSE) {
// Ask the user whether it's OK to close the window
rv = ConfirmClose(&confirmOK);
if (NS_FAILED(rv))
return rv;
} else {
confirmOK = (closePref == ALLOW_SCRIPT_CLOSE);
}
if (!confirmOK) {
// User clicked Cancel, so abort the close
return NS_OK;
}
}
}
nsCOMPtr<nsIJSContextStack> stack = nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1"); do_GetService("@mozilla.org/js/xpc/ContextStack;1");

Просмотреть файл

@ -214,6 +214,7 @@ protected:
const nsAReadableString& aOptions, const nsAReadableString& aOptions,
PRBool aDialog, jsval *argv, PRUint32 argc, PRBool aDialog, jsval *argv, PRUint32 argc,
nsISupports *aExtraArgument, nsIDOMWindow **aReturn); nsISupports *aExtraArgument, nsIDOMWindow **aReturn);
nsresult ConfirmClose(PRBool* aConfirmed);
static void CloseWindow(nsISupports* aWindow); static void CloseWindow(nsISupports* aWindow);
// Timeout Functions // Timeout Functions

Просмотреть файл

@ -334,6 +334,9 @@ pref("capability.principal.codebase.foo.granted", "UniversalFoo");
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
pref("dom.disable_open_during_load", false); pref("dom.disable_open_during_load", false);
// 0 = never allow scripts to close windows that weren't opened by script,
// 1 = prompt user, 2 = always allow. Default is prompt.
pref("dom.allow_scripts_to_close_windows", 1);
pref("javascript.enabled", true); pref("javascript.enabled", true);
pref("javascript.allow.mailnews", false); pref("javascript.allow.mailnews", false);