diff --git a/mozilla/caps/idl/nsIScriptSecurityManager.idl b/mozilla/caps/idl/nsIScriptSecurityManager.idl index b6f93aba70a..37f6ae1cfc5 100644 --- a/mozilla/caps/idl/nsIScriptSecurityManager.idl +++ b/mozilla/caps/idl/nsIScriptSecurityManager.idl @@ -40,12 +40,18 @@ interface nsIScriptSecurityManager : nsISupports boolean CheckURI(in nsIScriptContext cx, in nsIURI uri); + boolean HasSubjectPrincipal(); + nsIPrincipal GetSubjectPrincipal(); nsIPrincipal GetSystemPrincipal(); nsIPrincipal CreateCodebasePrincipal(in nsIURI aURI); + boolean CanExecuteScripts(in nsIPrincipal principal); + + boolean CanExecuteFunction(in voidStar jsFunction); + boolean CanEnableCapability(in nsIPrincipal principal, in string capability); void SetCanEnableCapability(in nsIPrincipal principal, in string capability, diff --git a/mozilla/caps/include/nsScriptSecurityManager.h b/mozilla/caps/include/nsScriptSecurityManager.h index e4cf544964e..9e6adc2db03 100644 --- a/mozilla/caps/include/nsScriptSecurityManager.h +++ b/mozilla/caps/include/nsScriptSecurityManager.h @@ -47,6 +47,9 @@ public: GetScriptSecurityManager(); private: + JSContext * + GetCurrentContext(); + NS_IMETHOD GetSubjectPrincipal(JSContext *aCx, nsIPrincipal **result); diff --git a/mozilla/caps/src/nsScriptSecurityManager.cpp b/mozilla/caps/src/nsScriptSecurityManager.cpp index 335731ab839..059f212bd94 100644 --- a/mozilla/caps/src/nsScriptSecurityManager.cpp +++ b/mozilla/caps/src/nsScriptSecurityManager.cpp @@ -185,18 +185,18 @@ nsScriptSecurityManager::CheckURI(nsIScriptContext *aContext, return NS_OK; } +NS_IMETHODIMP +nsScriptSecurityManager::HasSubjectPrincipal(PRBool *result) +{ + *result = GetCurrentContext() != nsnull; + return NS_OK; +} NS_IMETHODIMP nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **result) { - // Get JSContext from stack. - nsresult rv; - NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", - &rv); - if (NS_FAILED(rv)) - return NS_ERROR_FAILURE; - JSContext *cx; - if (NS_FAILED(stack->Peek(&cx))) + JSContext *cx = GetCurrentContext(); + if (!cx) return NS_ERROR_FAILURE; return GetSubjectPrincipal(cx, result); } @@ -229,6 +229,54 @@ nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI *aURI, return NS_OK; } + +NS_IMETHODIMP +nsScriptSecurityManager::CanExecuteScripts(nsIPrincipal *principal, + PRBool *result) +{ + nsIPref *mPrefs; + nsServiceManager::GetService(kPrefServiceCID, NS_GET_IID(nsIPref), + (nsISupports**) &mPrefs); + if (NS_FAILED(mPrefs->GetBoolPref("javascript.enabled", result))) { + // Default to enabled. + *result = PR_TRUE; + return NS_OK; + } + if (!*result) { + // JavaScript is disabled, but we must still execute system JavaScript + *result = (principal == mSystemPrincipal); + } + return NS_OK; +} + +NS_IMETHODIMP +nsScriptSecurityManager::CanExecuteFunction(void *jsFunc, + PRBool *result) +{ + nsIPref *mPrefs; + nsServiceManager::GetService(kPrefServiceCID, NS_GET_IID(nsIPref), + (nsISupports**) &mPrefs); + if (NS_FAILED(mPrefs->GetBoolPref("javascript.enabled", result))) { + // Default to enabled. + *result = PR_TRUE; + return NS_OK; + } + if (!*result) { + // norris TODO: figure out JSContext strategy, replace nsnulls below + // JavaScript is disabled, but we must still execute system JavaScript + JSScript *script = JS_GetFunctionScript(nsnull, (JSFunction *) jsFunc); + if (!script) + return NS_ERROR_FAILURE; + JSPrincipals *jsprin = JS_GetScriptPrincipals(nsnull, script); + if (!jsprin) + return NS_ERROR_FAILURE; + nsJSPrincipals *nsJSPrin = (nsJSPrincipals *) jsprin; + *result = (nsJSPrin->nsIPrincipalPtr == mSystemPrincipal); + } + return NS_OK; +} + + NS_IMETHODIMP nsScriptSecurityManager::CanEnableCapability(nsIPrincipal *principal, const char *capability, @@ -350,6 +398,20 @@ nsScriptSecurityManager::GetScriptSecurityManager() return ssecMan; } +JSContext * +nsScriptSecurityManager::GetCurrentContext() { + // Get JSContext from stack. + nsresult rv; + NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", + &rv); + if (NS_FAILED(rv)) + return nsnull; + JSContext *cx; + if (NS_FAILED(stack->Peek(&cx))) + return nsnull; + return cx; +} + NS_IMETHODIMP nsScriptSecurityManager::GetSubjectPrincipal(JSContext *aCx, nsIPrincipal **result) diff --git a/mozilla/dom/public/nsIScriptContext.h b/mozilla/dom/public/nsIScriptContext.h index e393c23f792..b70976b179a 100644 --- a/mozilla/dom/public/nsIScriptContext.h +++ b/mozilla/dom/public/nsIScriptContext.h @@ -45,29 +45,41 @@ class nsIScriptContext : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISCRIPTCONTEXT_IID) - /** - * Execute a script. - * - * @param aScript a string representing the script to be executed - * @param aScriptSize the length of aScript - * @param aRetValue return value - * - * @return NS_OK if the script was valid and got executed - * - **/ - NS_IMETHOD EvaluateString(const nsString& aScript, + // deprecated: remove later + NS_IMETHOD EvaluateString(const nsString& aScript, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined) = 0; - NS_IMETHOD EvaluateString(const nsString& aScript, + /** + * Execute a script. + * + * @param aScript a string representing the script to be executed + * @param aObj a JavaScript JSObject for the scope to execute in, or nsnull + * to use a default scope + * @param principal the principal that produced the script + * @param aURL the URL or filename for error messages + * @param aLineNo the starting line number for the script for error messages + * @param aRetValue the result of executing the script + * @param aIsUndefined true if the result of executing the script is the + * undefined value + * + * @return NS_OK if the script was valid and got executed + * + **/ + NS_IMETHOD EvaluateString(const nsString& aScript, + void *aObj, nsIPrincipal *principal, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined) = 0; + NS_IMETHOD CallFunction(void *aObj, void *aFunction, + PRUint32 argc, void *argv, + PRBool *aBoolResult) = 0; + /** * Return the global object. * diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index f0d2bce9811..e2af84a79bd 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -1633,7 +1633,6 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout) nsTimeoutImpl dummy_timeout; JSContext *cx; PRInt64 now; - jsval result; nsITimer *timer; nsresult rv; @@ -1691,35 +1690,18 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout) /* Hold the timeout in case expr or funobj releases its doc. */ HoldTimeout(timeout); mRunningTimeout = timeout; - NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv); - if (NS_FAILED(rv)) { - NS_RELEASE(temp); - NS_RELEASE(tempContext); - return PR_TRUE; - } - rv = stack->Push(cx); - // XXX Should check for rv. If failed, then what? if (timeout->expr) { /* Evaluate the timeout expression. */ -#if 0 - // V says it would be nice if we could have a chokepoint - // for calling scripts instead of making a bunch of - // ScriptEvaluated() calls to clean things up. MMP - PRBool isundefined; - mContext->EvaluateString(nsAutoString(timeout->expr), - timeout->filename, - timeout->lineno, nsAutoString(""), &isundefined); -#endif - JSPrincipals * jsprin; - timeout->principal->GetJSPrincipals(&jsprin); - JS_EvaluateUCScriptForPrincipals(cx, (JSObject *)mScriptObject, - jsprin, JS_GetStringChars(timeout->expr), - JS_GetStringLength(timeout->expr), timeout->filename, - timeout->lineno, &result); - JSPRINCIPALS_DROP(cx, jsprin); - } - else { + nsAutoString script = JS_GetStringChars(timeout->expr); + nsAutoString blank = ""; + PRBool isUndefined; + rv = mContext->EvaluateString(script, mScriptObject, + timeout->principal, + timeout->filename, + timeout->lineno, blank, + &isUndefined); + } else { PRInt64 lateness64; PRInt32 lateness; @@ -1729,11 +1711,17 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout) LL_L2I(lateness, lateness64); lateness = PR_IntervalToMilliseconds(lateness); timeout->argv[timeout->argc] = INT_TO_JSVAL((jsint)lateness); - JS_CallFunctionValue(cx, (JSObject *)mScriptObject, OBJECT_TO_JSVAL(timeout->funobj), - timeout->argc + 1, timeout->argv, &result); + PRBool aBoolResult; + rv = mContext->CallFunction(mScriptObject, timeout->funobj, + timeout->argc + 1, timeout->argv, + &aBoolResult); } - tempContext->ScriptEvaluated(); - rv = stack->Pop(nsnull); + if (NS_FAILED(rv)) { + NS_RELEASE(temp); + NS_RELEASE(tempContext); + return PR_TRUE; + } + mRunningTimeout = nsnull; /* If the temporary reference is the only one that is keeping the timeout around, the document was released and we should diff --git a/mozilla/dom/src/base/nsJSEnvironment.cpp b/mozilla/dom/src/base/nsJSEnvironment.cpp index f6e524ad89c..a201130e1aa 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.cpp +++ b/mozilla/dom/src/base/nsJSEnvironment.cpp @@ -123,53 +123,68 @@ nsJSContext::~nsJSContext() NS_IMPL_ISUPPORTS(nsJSContext, kIScriptContextIID); NS_IMETHODIMP -nsJSContext::EvaluateString(const nsString& aScript, +nsJSContext::EvaluateString(const nsString& aScript, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined) { - nsCOMPtr globalData; - nsCOMPtr principal; - nsCOMPtr global = GetGlobalObject(); - if (!global || NS_FAILED(global->QueryInterface(NS_GET_IID(nsIScriptGlobalObjectData), - (void**) getter_AddRefs(globalData)))) - { - return NS_ERROR_FAILURE; - } - if (NS_FAILED(globalData->GetPrincipal(getter_AddRefs(principal)))) - return NS_ERROR_FAILURE; - - return EvaluateString(aScript, principal, aURL, aLineNo, aRetValue, aIsUndefined); + return EvaluateString(aScript, nsnull, nsnull, aURL, aLineNo, aRetValue, aIsUndefined); } - NS_IMETHODIMP -nsJSContext::EvaluateString(const nsString& aScript, +nsJSContext::EvaluateString(const nsString& aScript, + void *jsObj, nsIPrincipal *principal, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined) { - nsresult rv; + if (!jsObj) + jsObj = JS_GetGlobalObject(mContext); NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; if (NS_FAILED(stack->Push(mContext))) return NS_ERROR_FAILURE; JSPrincipals *jsprin; - principal->GetJSPrincipals(&jsprin); + if (principal) { + principal->GetJSPrincipals(&jsprin); + } else { + // norris TODO: Using GetGlobalObject to get principals is unrelible. + nsCOMPtr globalData; + nsCOMPtr principal; + nsCOMPtr global = GetGlobalObject(); + if (!global || NS_FAILED(global->QueryInterface(NS_GET_IID(nsIScriptGlobalObjectData), + (void**) getter_AddRefs(globalData)))) + { + return NS_ERROR_FAILURE; + } + if (NS_FAILED(globalData->GetPrincipal(getter_AddRefs(principal)))) + return NS_ERROR_FAILURE; + principal->GetJSPrincipals(&jsprin); + } jsval val; - PRBool ret = ::JS_EvaluateUCScriptForPrincipals(mContext, - JS_GetGlobalObject(mContext), - jsprin, - (jschar*)aScript.GetUnicode(), - aScript.Length(), - aURL, - aLineNo, - &val); + NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager, + NS_SCRIPTSECURITYMANAGER_PROGID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + PRBool canExecute; + if (NS_FAILED(securityManager->CanExecuteScripts(principal, &canExecute))) + return NS_ERROR_FAILURE; + PRBool ret = PR_FALSE; + if (canExecute) { + ret = ::JS_EvaluateUCScriptForPrincipals(mContext, + (JSObject *)jsObj, + jsprin, + (jschar*)aScript.GetUnicode(), + aScript.Length(), + aURL, + aLineNo, + &val); + } JSPRINCIPALS_DROP(mContext, jsprin); if (ret) { *aIsUndefined = JSVAL_IS_VOID(val); @@ -177,6 +192,7 @@ nsJSContext::EvaluateString(const nsString& aScript, aRetValue.SetString(JS_GetStringChars(jsstring)); } else { + *aIsUndefined = PR_TRUE; aRetValue.Truncate(); } @@ -188,6 +204,44 @@ nsJSContext::EvaluateString(const nsString& aScript, return NS_OK; } +NS_IMETHODIMP +nsJSContext::CallFunction(void *aObj, void *aFunction, PRUint32 argc, + void *argv, PRBool *aBoolResult) +{ + nsresult rv; + NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager, + NS_SCRIPTSECURITYMANAGER_PROGID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + PRBool canExecute; + if (NS_FAILED(securityManager->CanExecuteFunction((JSFunction *)aFunction, + &canExecute))) + return NS_ERROR_FAILURE; + + NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + if (NS_FAILED(stack->Push(mContext))) + return NS_ERROR_FAILURE; + + jsval val; + PRBool ret = canExecute && + JS_CallFunction(mContext, (JSObject *)aObj, + (JSFunction *)aFunction, argc, + (jsval *)argv, &val); + *aBoolResult = ret + ? !JSVAL_IS_BOOLEAN(val) || JSVAL_TO_BOOLEAN(val) + : JS_TRUE; + + ScriptEvaluated(); + + if (NS_FAILED(stack->Pop(nsnull))) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + NS_IMETHODIMP_(nsIScriptGlobalObject*) nsJSContext::GetGlobalObject() { diff --git a/mozilla/dom/src/base/nsJSEnvironment.h b/mozilla/dom/src/base/nsJSEnvironment.h index 20b01a0c430..4794c9cf367 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.h +++ b/mozilla/dom/src/base/nsJSEnvironment.h @@ -40,17 +40,21 @@ public: NS_DECL_ISUPPORTS - NS_IMETHOD EvaluateString(const nsString& aScript, + NS_IMETHOD EvaluateString(const nsString& aScript, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined); - NS_IMETHOD EvaluateString(const nsString& aScript, + NS_IMETHOD EvaluateString(const nsString& aScript, + void *aObj, nsIPrincipal *principal, const char *aURL, PRUint32 aLineNo, nsString& aRetValue, PRBool* aIsUndefined); + NS_IMETHOD CallFunction(void *aObj, void *aFunction, + PRUint32 argc, void *argv, + PRBool *aBoolResult); NS_IMETHOD_(nsIScriptGlobalObject*) GetGlobalObject(); NS_IMETHOD_(void*) GetNativeContext(); NS_IMETHOD InitClasses(); diff --git a/mozilla/dom/src/events/nsJSDOMEventListener.cpp b/mozilla/dom/src/events/nsJSDOMEventListener.cpp index 812d5df7f24..63e5bf0c773 100644 --- a/mozilla/dom/src/events/nsJSDOMEventListener.cpp +++ b/mozilla/dom/src/events/nsJSDOMEventListener.cpp @@ -17,6 +17,8 @@ */ #include "nsJSDOMEventListener.h" #include "nsString.h" +#include "nsIServiceManager.h" +#include "nsIScriptSecurityManager.h" static NS_DEFINE_IID(kIScriptEventListenerIID, NS_ISCRIPTEVENTLISTENER_IID); static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); @@ -76,16 +78,11 @@ nsresult nsJSDOMEventListener::HandleEvent(nsIDOMEvent* aEvent) } argv[0] = OBJECT_TO_JSVAL(eventObj); - if (PR_TRUE == JS_CallFunction(mContext, mJSObj, mJSFun, 1, argv, &result)) { - mScriptCX->ScriptEvaluated(); - if (JSVAL_IS_BOOLEAN(result) && JSVAL_TO_BOOLEAN(result) == JS_FALSE) { - return NS_ERROR_FAILURE; - } - return NS_OK; + PRBool jsBoolResult; + if (NS_FAILED(mScriptCX->CallFunction(mJSObj, mJSFun, 1, argv, &jsBoolResult))) { + return NS_ERROR_FAILURE; } - mScriptCX->ScriptEvaluated(); - - return NS_ERROR_FAILURE; + return jsBoolResult ? NS_OK : NS_ERROR_FAILURE; } nsresult nsJSDOMEventListener::CheckIfEqual(nsIScriptEventListener *aListener) diff --git a/mozilla/dom/src/events/nsJSEventListener.cpp b/mozilla/dom/src/events/nsJSEventListener.cpp index 8e15e4382c6..2079dfd72b8 100644 --- a/mozilla/dom/src/events/nsJSEventListener.cpp +++ b/mozilla/dom/src/events/nsJSEventListener.cpp @@ -20,6 +20,7 @@ #include "nsIScriptEventListener.h" #include "nsIServiceManager.h" #include "nsIJSContextStack.h" +#include "nsIScriptSecurityManager.h" static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); @@ -64,12 +65,11 @@ NS_IMPL_RELEASE(nsJSEventListener) nsresult nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent) { - jsval funval, result; + jsval funval; jsval argv[1]; JSObject *eventObj; char* eventChars; nsAutoString eventString; - nsresult rv; if (NS_OK != aEvent->GetType(eventString)) { //JS can't handle this event yet or can't handle it at all @@ -96,30 +96,18 @@ nsresult nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent) return NS_ERROR_FAILURE; } - NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv); - if (NS_FAILED(rv)) { - return rv; - } - - rv = stack->Push(mContext); - if (NS_FAILED(rv)) { - return rv; - } - argv[0] = OBJECT_TO_JSVAL(eventObj); - PRBool ok = JS_CallFunctionValue(mContext, mJSObj, funval, 1, argv, &result); - - mScriptCX->ScriptEvaluated(); - rv = stack->Pop(nsnull); - - if (PR_TRUE == ok) { - if (JSVAL_IS_BOOLEAN(result) && JSVAL_TO_BOOLEAN(result) == JS_FALSE) { - aEvent->PreventDefault(); - } - return NS_OK; + JSFunction *jsFun = JS_ValueToFunction(mContext, funval); + PRBool jsBoolResult; + if (!jsFun || NS_FAILED(mScriptCX->CallFunction(mJSObj, jsFun, 1, argv, + &jsBoolResult))) + { + return NS_ERROR_FAILURE; } + if (!jsBoolResult) + aEvent->PreventDefault(); - return NS_ERROR_FAILURE; + return NS_OK; } /* diff --git a/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp b/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp index 15493cff177..2f561b0e315 100644 --- a/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp +++ b/mozilla/dom/src/jsurl/nsJSProtocolHandler.cpp @@ -82,6 +82,15 @@ public: NS_SCRIPTSECURITYMANAGER_PROGID, &result); if (NS_FAILED(result)) return NS_ERROR_FAILURE; + PRBool hasPrincipal; + if (NS_FAILED(securityManager->HasSubjectPrincipal(&hasPrincipal))) + return NS_ERROR_FAILURE; + if (!hasPrincipal) { + // Must be loaded as a result of a user action on a HTML element + // with a javascript: HREF attribute + // TODO: need to find URI of enclosing page + return NS_OK; + } if (NS_FAILED(securityManager->GetSubjectPrincipal(&mPrincipal))) return NS_ERROR_FAILURE; return NS_OK; @@ -151,8 +160,9 @@ public: // Finally, we have everything needed to evaluate the expression. nsAutoString ret; PRBool isUndefined; - rv = scriptContext->EvaluateString(nsString(jsExpr), mPrincipal, - nsnull, 0, ret, &isUndefined); + rv = scriptContext->EvaluateString(nsString(jsExpr), nsnull, + mPrincipal, nsnull, 0, ret, + &isUndefined); nsCRT::free(jsExpr); if (NS_FAILED(rv)) { rv = NS_ERROR_MALFORMED_URI;