Add ability to disable JS. Fix 13978 shopping at webvan.com crashes

This commit is contained in:
norris%netscape.com 1999-09-17 20:13:52 +00:00
Родитель 96e61e0abb
Коммит d1e37156bd
10 изменённых файлов: 236 добавлений и 112 удалений

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

@ -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,

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

@ -47,6 +47,9 @@ public:
GetScriptSecurityManager();
private:
JSContext *
GetCurrentContext();
NS_IMETHOD
GetSubjectPrincipal(JSContext *aCx, nsIPrincipal **result);

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

@ -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)

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

@ -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.
*

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

@ -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

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

@ -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<nsIScriptGlobalObjectData> globalData;
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIScriptGlobalObject> 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<nsIScriptGlobalObjectData> globalData;
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIScriptGlobalObject> 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()
{

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

@ -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();

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

@ -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)

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

@ -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;
}
/*

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

@ -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;