mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 968335 - Implement GetCallerPrincipalOverride. r=bz
This commit is contained in:
parent
6c95fae0b3
commit
7149c177ee
@ -155,6 +155,45 @@ GetIncumbentGlobal()
|
||||
return ScriptSettingsStack::Ref().IncumbentGlobal();
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
GetWebIDLCallerPrincipal()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ScriptSettingsStackEntry *entry = ScriptSettingsStack::Ref().EntryPoint();
|
||||
|
||||
// If we have an entry point that is not the system singleton, we know it
|
||||
// must be an AutoEntryScript.
|
||||
if (!entry || entry->IsSystemSingleton()) {
|
||||
return nullptr;
|
||||
}
|
||||
AutoEntryScript* aes = static_cast<AutoEntryScript*>(entry);
|
||||
|
||||
// We can't yet rely on the Script Settings Stack to properly determine the
|
||||
// entry script, because there are still lots of places in the tree where we
|
||||
// don't yet use an AutoEntryScript (bug 951991 tracks this work). In the
|
||||
// mean time though, we can make some observations to hack around the
|
||||
// problem:
|
||||
//
|
||||
// (1) All calls into JS-implemented WebIDL go through CallSetup, which goes
|
||||
// through AutoEntryScript.
|
||||
// (2) The top candidate entry point in the Script Settings Stack is the
|
||||
// entry point if and only if no other JSContexts have been pushed on
|
||||
// top of the push made by that entry's AutoEntryScript.
|
||||
//
|
||||
// Because of (1), all of the cases where we might return a non-null
|
||||
// WebIDL Caller are guaranteed to have put an entry on the Script Settings
|
||||
// Stack, so we can restrict our search to that. Moreover, (2) gives us a
|
||||
// criterion to determine whether an entry in the Script Setting Stack means
|
||||
// that we should return a non-null WebIDL Caller.
|
||||
//
|
||||
// Once we fix bug 951991, this can all be simplified.
|
||||
if (!aes->mCxPusher.ref().IsStackTop()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aes->mWebIDLCallerPrincipal;
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsCxPusher.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
@ -38,6 +39,24 @@ nsIGlobalObject* BrokenGetEntryGlobal();
|
||||
// can mostly be inferred from the JS stack.
|
||||
nsIGlobalObject* GetIncumbentGlobal();
|
||||
|
||||
// JS-implemented WebIDL presents an interesting situation with respect to the
|
||||
// subject principal. A regular C++-implemented API can simply examine the
|
||||
// compartment of the most-recently-executed script, and use that to infer the
|
||||
// responsible party. However, JS-implemented APIs are run with system
|
||||
// principal, and thus clobber the subject principal of the script that
|
||||
// invoked the API. So we have to do some extra work to keep track of this
|
||||
// information.
|
||||
//
|
||||
// We therefore implement the following behavior:
|
||||
// * Each Script Settings Object has an optional WebIDL Caller Principal field.
|
||||
// This defaults to null.
|
||||
// * When we push an Entry Point in preparation to run a JS-implemented WebIDL
|
||||
// callback, we grab the subject principal at the time of invocation, and
|
||||
// store that as the WebIDL Caller Principal.
|
||||
// * When non-null, callers can query this principal from script via an API on
|
||||
// Components.utils.
|
||||
nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
struct ScriptSettingsStackEntry {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
@ -79,11 +98,17 @@ public:
|
||||
JSContext* aCx = nullptr);
|
||||
~AutoEntryScript();
|
||||
|
||||
void SetWebIDLCallerPrincipal(nsIPrincipal *aPrincipal) {
|
||||
mWebIDLCallerPrincipal = aPrincipal;
|
||||
}
|
||||
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
nsCOMPtr<nsIPrincipal> mWebIDLCallerPrincipal;
|
||||
mozilla::Maybe<AutoCxPusher> mCxPusher;
|
||||
mozilla::Maybe<JSAutoCompartment> mAc; // This can de-Maybe-fy when mCxPusher
|
||||
// goes away.
|
||||
friend nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -49,7 +49,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment)
|
||||
JSCompartment* aCompartment,
|
||||
bool aIsJSImplementedWebIDL)
|
||||
: mCx(nullptr)
|
||||
, mCompartment(aCompartment)
|
||||
, mErrorResult(aRv)
|
||||
@ -59,6 +60,14 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::EnterMicroTask();
|
||||
}
|
||||
|
||||
// Compute the caller's subject principal (if necessary) early, before we
|
||||
// do anything that might perturb the relevant state.
|
||||
nsIPrincipal* webIDLCallerPrincipal = nullptr;
|
||||
if (aIsJSImplementedWebIDL) {
|
||||
webIDLCallerPrincipal = nsContentUtils::GetSubjectPrincipal();
|
||||
}
|
||||
|
||||
// We need to produce a useful JSContext here. Ideally one that the callback
|
||||
// is in some sense associated with, so that we can sort of treat it as a
|
||||
// "script entry point". Though once we actually have script entry points,
|
||||
@ -112,6 +121,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
}
|
||||
|
||||
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
|
||||
mAutoEntryScript.ref().SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
|
||||
if (aCallback->IncumbentGlobalOrNull()) {
|
||||
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
|
||||
}
|
||||
|
@ -154,10 +154,11 @@ protected:
|
||||
*/
|
||||
public:
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aCompartment
|
||||
// needs to be set to the caller's compartment.
|
||||
// needs to be set to the compartment in which exceptions will be rethrown.
|
||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr);
|
||||
JSCompartment* aCompartment = nullptr,
|
||||
bool aIsJSImplementedWebIDL = false);
|
||||
~CallSetup();
|
||||
|
||||
JSContext* GetContext() const
|
||||
|
@ -11289,7 +11289,8 @@ class CallbackMember(CGNativeMember):
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
callSetup += ", eRethrowContentExceptions, aCompartment"
|
||||
callSetup += ", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ "
|
||||
callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
|
||||
else:
|
||||
callSetup += ", aExceptionHandling"
|
||||
callSetup += ");"
|
||||
|
Loading…
Reference in New Issue
Block a user