From 834db6cfe837cf7da33b2dcce810669a25300dfb Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Thu, 8 Aug 2024 16:35:19 +0000 Subject: [PATCH] Bug 1906744 - Check if constructor is enabled before installing named property. r=mccr8,dom-storage-reviewers,janv,asuth,eemeli Differential Revision: https://phabricator.services.mozilla.com/D216671 --- dom/bindings/BindingDeclarations.h | 29 ++- dom/bindings/BindingUtils.cpp | 10 +- dom/bindings/BindingUtils.h | 8 + dom/bindings/Codegen.py | 166 ++++++++------- dom/bindings/WebIDLGlobalNameHash.cpp | 12 +- dom/cache/CacheStorage.cpp | 7 +- dom/cache/CacheStorage.h | 3 +- dom/indexedDB/IndexedDatabaseManager.cpp | 22 +- dom/webidl/DOMLocalization.webidl | 2 +- dom/webidl/Localization.webidl | 2 +- dom/workers/RegisterBindings.cpp | 7 +- .../autoconfig/src/nsJSConfigTriggers.cpp | 2 +- intl/l10n/Localization.cpp | 9 + intl/l10n/Localization.h | 2 + js/xpconnect/src/Sandbox.cpp | 192 +++++------------- 15 files changed, 225 insertions(+), 248 deletions(-) diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index c723af00212e..83919e7e5a95 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -548,14 +548,33 @@ class SystemCallerGuarantee { operator CallerType() const { return CallerType::System; } }; +enum class DefineInterfaceProperty { + No, + CheckExposure, + Always, +}; + class ProtoAndIfaceCache; -typedef void (*CreateInterfaceObjectsMethod)(JSContext* aCx, - JS::Handle aGlobal, - ProtoAndIfaceCache& aCache, - bool aDefineOnGlobal); +using CreateInterfaceObjectsMethod = + void (*)(JSContext*, JS::Handle, ProtoAndIfaceCache&, + DefineInterfaceProperty aDefineOnGlobal); + +// GetPerInterfaceObjectHandle has 3 possible behaviours for defining the named +// properties on the global for an interface or namespace when it creates an +// interface or namespace object. aDefineOnGlobal can be used to pick the +// behaviour. GetPerInterfaceObjectHandle either: +// +// * does not define any properties on the global object +// (for DefineInterfaceProperty::No), +// * checks whether the interface is exposed in the global object before +// defining properties (for DefineInterfaceProperty::CheckExposure), +// * always defines properties (for DefineInterfaceProperty::Always). +// +// Callers should be careful when passing DefineInterfaceProperty::Always and +// make sure to check exposure themselves if needed. JS::Handle GetPerInterfaceObjectHandle( JSContext* aCx, size_t aSlotId, CreateInterfaceObjectsMethod aCreator, - bool aDefineOnGlobal); + DefineInterfaceProperty aDefineOnGlobal); namespace binding_detail { diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index e819bf688fa5..b8715920b91a 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -3665,8 +3665,8 @@ bool GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs, // JS::GetRealmGlobalOrNull should not be returning null here, because we // have live objects in the Realm. JSAutoRealm ar(aCx, JS::GetRealmGlobalOrNull(realm)); - aDesiredProto.set( - GetPerInterfaceObjectHandle(aCx, aProtoId, aCreator, true)); + aDesiredProto.set(GetPerInterfaceObjectHandle( + aCx, aProtoId, aCreator, DefineInterfaceProperty::CheckExposure)); if (!aDesiredProto) { return false; } @@ -3797,8 +3797,8 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp, // makes sense to start with: https://github.com/whatwg/html/issues/3575 { JSAutoRealm ar(aCx, newTarget); - JS::Handle constructor = - GetPerInterfaceObjectHandle(aCx, aConstructorId, aCreator, true); + JS::Handle constructor = GetPerInterfaceObjectHandle( + aCx, aConstructorId, aCreator, DefineInterfaceProperty::CheckExposure); if (!constructor) { return false; } @@ -4202,7 +4202,7 @@ JSObject* UnprivilegedJunkScopeOrWorkerGlobal(const fallible_t&) { JS::Handle GetPerInterfaceObjectHandle( JSContext* aCx, size_t aSlotId, CreateInterfaceObjectsMethod aCreator, - bool aDefineOnGlobal) { + DefineInterfaceProperty aDefineOnGlobal) { /* Make sure our global is sane. Hopefully we can remove this sometime */ JSObject* global = JS::CurrentGlobalOrNull(aCx); if (!(JS::GetClass(global)->flags & JSCLASS_DOM_GLOBAL)) { diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 6bcefbf31580..49c23890f1eb 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -3369,6 +3369,14 @@ class StringIdChars { already_AddRefed CreateRejectedPromiseFromThrownException( JSContext* aCx, ErrorResult& aError); +template +inline bool ShouldExpose(JSContext* aCx, JS::Handle aGlobal, + DefineInterfaceProperty aDefine) { + return aDefine == DefineInterfaceProperty::Always || + (aDefine == DefineInterfaceProperty::CheckExposure && + ConstructorEnabled(aCx, aGlobal)); +} + } // namespace binding_detail } // namespace dom diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 659d7e4b2001..d70f9d528d77 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3494,7 +3494,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): Argument("JSContext*", "aCx"), Argument("JS::Handle", "aGlobal"), Argument("ProtoAndIfaceCache&", "aProtoAndIfaceCache"), - Argument("bool", "aDefineOnGlobal"), + Argument("DefineInterfaceProperty", "aDefineOnGlobal"), ] CGAbstractMethod.__init__( self, descriptor, "CreateInterfaceObjects", "void", args, static=static @@ -3505,6 +3505,19 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): def definition_body(self): needInterfaceObject = self.descriptor.interface.hasInterfaceObject() + if needInterfaceObject and self.descriptor.isExposedConditionally(): + # This code might be called when we're trying to create an object + # in a non-system compartment, for example when system code is + # calling a constructor through Xrays. In that case we do want to + # create an interface object in the non-system compartment, but we + # don't want to expose the name on the non-system global if the + # interface itself is marked as ChromeOnly. + defineOnGlobal = ( + "ShouldExpose<%s::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal)" + % toBindingNamespace(self.descriptor.name) + ) + else: + defineOnGlobal = "aDefineOnGlobal != DefineInterfaceProperty::No" if needInterfaceObject: (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter( self.descriptor @@ -3572,13 +3585,15 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): interfaceCache, ${properties}, ${chromeProperties}, - "${name}", aDefineOnGlobal); + "${name}", + ${defineOnGlobal}); """, interfaceCache=interfaceCache, constructorProto=constructorProto, properties=properties, chromeProperties=chromeProperties, name=name, + defineOnGlobal=defineOnGlobal, ) return CGList( [ @@ -3659,7 +3674,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): interfaceCache, ${properties}, ${chromeProperties}, - "${name}", aDefineOnGlobal, + "${name}", + ${defineOnGlobal}, ${unscopableNames}, ${isGlobal}, ${legacyWindowAliases}); @@ -3674,6 +3690,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): properties=properties, chromeProperties=chromeProperties, name=name, + defineOnGlobal=defineOnGlobal, unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr", isGlobal=toStringBool(isGlobal), legacyWindowAliases="legacyWindowAliases" @@ -3913,6 +3930,40 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): ).define() +class CGCreateAndDefineOnGlobalMethod(CGAbstractMethod): + """ + A method for creating the interface or namespace object and defining + properties for it on the global. + """ + + def __init__(self, descriptor): + CGAbstractMethod.__init__( + self, + descriptor, + "CreateAndDefineOnGlobal", + "bool", + [ + Argument("JSContext*", "aCx"), + ], + inline=True, + ) + + def definition_body(self): + return fill( + """ + // Get the interface or namespace object for this class. This will + // create the object as needed and always define the properties for + // it on the global. The caller should make sure the interface or + // namespace is exposed on the global before calling this. + return GetPerInterfaceObjectHandle(aCx, constructors::id::${name}, + &CreateInterfaceObjects, + DefineInterfaceProperty::Always); + + """, + name=self.descriptor.name, + ) + + class CGGetProtoObjectHandleMethod(CGAbstractMethod): """ A method for getting the interface prototype object. @@ -3937,7 +3988,7 @@ class CGGetProtoObjectHandleMethod(CGAbstractMethod): object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::${name}, &CreateInterfaceObjects, - /* aDefineOnGlobal = */ true); + DefineInterfaceProperty::CheckExposure); """, name=self.descriptor.name, @@ -3975,7 +4026,6 @@ class CGGetConstructorObjectHandleMethod(CGAbstractMethod): "JS::Handle", [ Argument("JSContext*", "aCx"), - Argument("bool", "aDefineOnGlobal", "true"), ], inline=True, ) @@ -3988,7 +4038,7 @@ class CGGetConstructorObjectHandleMethod(CGAbstractMethod): return GetPerInterfaceObjectHandle(aCx, constructors::id::${name}, &CreateInterfaceObjects, - aDefineOnGlobal); + DefineInterfaceProperty::CheckExposure); """, name=self.descriptor.name, ) @@ -17172,6 +17222,11 @@ class CGDescriptor(CGThing): if descriptor.interface.hasInterfaceObject(): cgThings.append(CGGetConstructorObjectHandleMethod(descriptor)) cgThings.append(CGGetConstructorObjectMethod(descriptor)) + cgThings.append( + CGCreateAndDefineOnGlobalMethod( + descriptor, + ) + ) # See whether we need to generate cross-origin property arrays. if needCrossOriginPropertyArrays: @@ -18355,6 +18410,21 @@ class CGDictionary(CGThing): return all(CGDictionary.typeSafeToJSONify(m.type) for m in dictionary.members) +def RegisterNonWindowBindings(descriptors): + conditions = [] + for desc in descriptors: + bindingNS = toBindingNamespace(desc.name) + condition = "!%s::CreateAndDefineOnGlobal(aCx)" % bindingNS + if desc.isExposedConditionally(): + condition = "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS + condition + conditions.append(condition) + lines = [ + CGIfWrapper(CGGeneric("return false;\n"), condition) for condition in conditions + ] + lines.append(CGGeneric("return true;\n")) + return CGList(lines, "\n").define() + + class CGRegisterWorkerBindings(CGAbstractMethod): def __init__(self, config): CGAbstractMethod.__init__( @@ -18367,24 +18437,11 @@ class CGRegisterWorkerBindings(CGAbstractMethod): self.config = config def definition_body(self): - descriptors = self.config.getDescriptors( - hasInterfaceObject=True, isExposedInAnyWorker=True, register=True + return RegisterNonWindowBindings( + self.config.getDescriptors( + hasInterfaceObject=True, isExposedInAnyWorker=True, register=True + ) ) - conditions = [] - for desc in descriptors: - bindingNS = toBindingNamespace(desc.name) - condition = "!%s::GetConstructorObject(aCx)" % bindingNS - if desc.isExposedConditionally(): - condition = ( - "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS + condition - ) - conditions.append(condition) - lines = [ - CGIfWrapper(CGGeneric("return false;\n"), condition) - for condition in conditions - ] - lines.append(CGGeneric("return true;\n")) - return CGList(lines, "\n").define() class CGRegisterWorkerDebuggerBindings(CGAbstractMethod): @@ -18399,24 +18456,11 @@ class CGRegisterWorkerDebuggerBindings(CGAbstractMethod): self.config = config def definition_body(self): - descriptors = self.config.getDescriptors( - hasInterfaceObject=True, isExposedInWorkerDebugger=True, register=True + return RegisterNonWindowBindings( + self.config.getDescriptors( + hasInterfaceObject=True, isExposedInWorkerDebugger=True, register=True + ) ) - conditions = [] - for desc in descriptors: - bindingNS = toBindingNamespace(desc.name) - condition = "!%s::GetConstructorObject(aCx)" % bindingNS - if desc.isExposedConditionally(): - condition = ( - "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS + condition - ) - conditions.append(condition) - lines = [ - CGIfWrapper(CGGeneric("return false;\n"), condition) - for condition in conditions - ] - lines.append(CGGeneric("return true;\n")) - return CGList(lines, "\n").define() class CGRegisterWorkletBindings(CGAbstractMethod): @@ -18431,24 +18475,11 @@ class CGRegisterWorkletBindings(CGAbstractMethod): self.config = config def definition_body(self): - descriptors = self.config.getDescriptors( - hasInterfaceObject=True, isExposedInAnyWorklet=True, register=True + return RegisterNonWindowBindings( + self.config.getDescriptors( + hasInterfaceObject=True, isExposedInAnyWorklet=True, register=True + ) ) - conditions = [] - for desc in descriptors: - bindingNS = toBindingNamespace(desc.name) - condition = "!%s::GetConstructorObject(aCx)" % bindingNS - if desc.isExposedConditionally(): - condition = ( - "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS + condition - ) - conditions.append(condition) - lines = [ - CGIfWrapper(CGGeneric("return false;\n"), condition) - for condition in conditions - ] - lines.append(CGGeneric("return true;\n")) - return CGList(lines, "\n").define() class CGRegisterShadowRealmBindings(CGAbstractMethod): @@ -18463,24 +18494,11 @@ class CGRegisterShadowRealmBindings(CGAbstractMethod): self.config = config def definition_body(self): - descriptors = self.config.getDescriptors( - hasInterfaceObject=True, isExposedInShadowRealms=True, register=True + return RegisterNonWindowBindings( + self.config.getDescriptors( + hasInterfaceObject=True, isExposedInShadowRealms=True, register=True + ) ) - conditions = [] - for desc in descriptors: - bindingNS = toBindingNamespace(desc.name) - condition = "!%s::GetConstructorObject(aCx)" % bindingNS - if desc.isExposedConditionally(): - condition = ( - "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS + condition - ) - conditions.append(condition) - lines = [ - CGIfWrapper(CGGeneric("return false;\n"), condition) - for condition in conditions - ] - lines.append(CGGeneric("return true;\n")) - return CGList(lines, "\n").define() def BindingNamesOffsetEnum(name): diff --git a/dom/bindings/WebIDLGlobalNameHash.cpp b/dom/bindings/WebIDLGlobalNameHash.cpp index 24e48a343fc0..9e87c8953673 100644 --- a/dom/bindings/WebIDLGlobalNameHash.cpp +++ b/dom/bindings/WebIDLGlobalNameHash.cpp @@ -33,7 +33,7 @@ static JSObject* FindNamedConstructorForXray( JSContext* aCx, JS::Handle aId, const WebIDLNameTableEntry* aEntry) { JSObject* interfaceObject = GetPerInterfaceObjectHandle(aCx, aEntry->mConstructorId, aEntry->mCreate, - /* aDefineOnGlobal = */ false); + DefineInterfaceProperty::No); if (!interfaceObject) { return nullptr; } @@ -161,10 +161,13 @@ bool WebIDLGlobalNameHash::DefineIfEnabled( return true; } + // We've already checked whether the interface is enabled (see + // checkEnabledForScope above), so it's fine to pass + // DefineInterfaceProperty::Always here. JS::Rooted interfaceObject( aCx, GetPerInterfaceObjectHandle(aCx, entry->mConstructorId, entry->mCreate, - /* aDefineOnGlobal = */ true)); + DefineInterfaceProperty::Always)); if (NS_WARN_IF(!interfaceObject)) { return Throw(aCx, NS_ERROR_FAILURE); } @@ -235,9 +238,12 @@ bool WebIDLGlobalNameHash::ResolveForSystemGlobal(JSContext* aCx, // Look up the corresponding entry in the name table, and resolve if enabled. const WebIDLNameTableEntry* entry = GetEntry(aId.toLinearString()); if (entry && (!entry->mEnabled || entry->mEnabled(aCx, aObj))) { + // We've already checked whether the interface is enabled (see + // entry->mEnabled above), so it's fine to pass + // DefineInterfaceProperty::Always here. if (NS_WARN_IF(!GetPerInterfaceObjectHandle( aCx, entry->mConstructorId, entry->mCreate, - /* aDefineOnGlobal = */ true))) { + DefineInterfaceProperty::Always))) { return Throw(aCx, NS_ERROR_FAILURE); } diff --git a/dom/cache/CacheStorage.cpp b/dom/cache/CacheStorage.cpp index 7a1594d203c2..4fd67102eb0e 100644 --- a/dom/cache/CacheStorage.cpp +++ b/dom/cache/CacheStorage.cpp @@ -226,14 +226,15 @@ already_AddRefed CacheStorage::CreateOnWorker( } // static -bool CacheStorage::DefineCaches(JSContext* aCx, JS::Handle aGlobal) { +bool CacheStorage::DefineCachesForSandbox(JSContext* aCx, + JS::Handle aGlobal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_DIAGNOSTIC_ASSERT(JS::GetClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL, "Passed object is not a global object!"); js::AssertSameCompartment(aCx, aGlobal); - if (NS_WARN_IF(!CacheStorage_Binding::GetConstructorObject(aCx) || - !Cache_Binding::GetConstructorObject(aCx))) { + if (NS_WARN_IF(!CacheStorage_Binding::CreateAndDefineOnGlobal(aCx) || + !Cache_Binding::CreateAndDefineOnGlobal(aCx))) { return false; } diff --git a/dom/cache/CacheStorage.h b/dom/cache/CacheStorage.h index 3bfbece08bdf..fe4ab68e6016 100644 --- a/dom/cache/CacheStorage.h +++ b/dom/cache/CacheStorage.h @@ -52,7 +52,8 @@ class CacheStorage final : public nsISupports, Namespace aNamespace, nsIGlobalObject* aGlobal, WorkerPrivate* aWorkerPrivate, ErrorResult& aRv); - static bool DefineCaches(JSContext* aCx, JS::Handle aGlobal); + static bool DefineCachesForSandbox(JSContext* aCx, + JS::Handle aGlobal); // webidl interface methods already_AddRefed Match(JSContext* aCx, diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index 8120b97381d8..12d90604a7e0 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -390,17 +390,17 @@ bool IndexedDatabaseManager::ResolveSandboxBinding(JSContext* aCx) { return false; } - if (!IDBCursor_Binding::GetConstructorObject(aCx) || - !IDBCursorWithValue_Binding::GetConstructorObject(aCx) || - !IDBDatabase_Binding::GetConstructorObject(aCx) || - !IDBFactory_Binding::GetConstructorObject(aCx) || - !IDBIndex_Binding::GetConstructorObject(aCx) || - !IDBKeyRange_Binding::GetConstructorObject(aCx) || - !IDBObjectStore_Binding::GetConstructorObject(aCx) || - !IDBOpenDBRequest_Binding::GetConstructorObject(aCx) || - !IDBRequest_Binding::GetConstructorObject(aCx) || - !IDBTransaction_Binding::GetConstructorObject(aCx) || - !IDBVersionChangeEvent_Binding::GetConstructorObject(aCx)) { + if (!IDBCursor_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBCursorWithValue_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBDatabase_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBFactory_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBIndex_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBKeyRange_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBObjectStore_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBOpenDBRequest_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBRequest_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBTransaction_Binding::CreateAndDefineOnGlobal(aCx) || + !IDBVersionChangeEvent_Binding::CreateAndDefineOnGlobal(aCx)) { return false; } diff --git a/dom/webidl/DOMLocalization.webidl b/dom/webidl/DOMLocalization.webidl index b229f37c5e3d..1eb64a9bb4c9 100644 --- a/dom/webidl/DOMLocalization.webidl +++ b/dom/webidl/DOMLocalization.webidl @@ -24,7 +24,7 @@ * */ -[Func="IsChromeOrUAWidget", Exposed=Window] +[Func="mozilla::intl::Localization::IsAPIEnabled", Exposed=Window] interface DOMLocalization : Localization { /** * Constructor arguments: diff --git a/dom/webidl/Localization.webidl b/dom/webidl/Localization.webidl index 8eceec433b65..20c075d9da1a 100644 --- a/dom/webidl/Localization.webidl +++ b/dom/webidl/Localization.webidl @@ -59,7 +59,7 @@ dictionary L10nMessage { * - formatMessages - format multiple compound messages * */ -[Func="IsChromeOrUAWidget", Exposed=Window] +[Func="mozilla::intl::Localization::IsAPIEnabled", Exposed=Window] interface Localization { /** * Constructor arguments: diff --git a/dom/workers/RegisterBindings.cpp b/dom/workers/RegisterBindings.cpp index 4c33b1e4c540..8bd734a52cf5 100644 --- a/dom/workers/RegisterBindings.cpp +++ b/dom/workers/RegisterBindings.cpp @@ -37,11 +37,8 @@ bool WorkerPrivate::RegisterDebuggerBindings(JSContext* aCx, return false; } - if (!ChromeUtils_Binding::GetConstructorObject(aCx)) { - return false; - } - - if (!DebuggerNotificationObserver_Binding::GetConstructorObject(aCx)) { + if (!ChromeUtils_Binding::CreateAndDefineOnGlobal(aCx) || + !DebuggerNotificationObserver_Binding::CreateAndDefineOnGlobal(aCx)) { return false; } diff --git a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp index e0b4324f4004..00813392f110 100644 --- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp +++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp @@ -77,7 +77,7 @@ nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled) { } // Define ChromeUtils for ChromeUtils.import. - if (!mozilla::dom::ChromeUtils_Binding::GetConstructorObject(cx)) { + if (!mozilla::dom::ChromeUtils_Binding::CreateAndDefineOnGlobal(cx)) { return NS_ERROR_FAILURE; } diff --git a/intl/l10n/Localization.cpp b/intl/l10n/Localization.cpp index 0d6f1f988228..eaf21909e4a3 100644 --- a/intl/l10n/Localization.cpp +++ b/intl/l10n/Localization.cpp @@ -6,9 +6,11 @@ #include "Localization.h" #include "nsIObserverService.h" +#include "xpcpublic.h" #include "mozilla/BasePrincipal.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" +#include "mozilla/dom/Document.h" #include "mozilla/dom/PromiseNativeHandler.h" #define INTL_APP_LOCALES_CHANGED "intl:app-locales-changed" @@ -148,6 +150,13 @@ Localization::Localization(nsIGlobalObject* aGlobal, bool aIsSync, RegisterObservers(); } +/* static */ +bool Localization::IsAPIEnabled(JSContext* aCx, JSObject* aObject) { + JS::Rooted obj(aCx, aObject); + return Document::DocumentSupportsL10n(aCx, obj) || + IsChromeOrUAWidget(aCx, obj); +} + already_AddRefed Localization::Constructor( const GlobalObject& aGlobal, const Sequence& aResourceIds, bool aIsSync, diff --git a/intl/l10n/Localization.h b/intl/l10n/Localization.h index d39283652080..a22802758d4c 100644 --- a/intl/l10n/Localization.h +++ b/intl/l10n/Localization.h @@ -84,6 +84,8 @@ class Localization : public nsIObserver, nsIObserver) NS_DECL_NSIOBSERVER + static bool IsAPIEnabled(JSContext* aCx, JSObject* aObject); + static already_AddRefed Constructor( const dom::GlobalObject& aGlobal, const dom::Sequence& aResourceIds, diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 31220f17de32..33ed044c73e9 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -83,6 +83,7 @@ #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/SelectionBinding.h" #include "mozilla/dom/StorageManager.h" +#include "mozilla/dom/StorageManagerBinding.h" #include "mozilla/dom/TextDecoderBinding.h" #include "mozilla/dom/TextEncoderBinding.h" #include "mozilla/dom/URLBinding.h" @@ -352,9 +353,9 @@ bool xpc::SandboxCreateFetch(JSContext* cx, JS::Handle obj) { MOZ_ASSERT(JS_IsGlobalObject(obj)); return JS_DefineFunction(cx, obj, "fetch", SandboxFetchPromise, 2, 0) && - dom::Request_Binding::GetConstructorObject(cx) && - dom::Response_Binding::GetConstructorObject(cx) && - dom::Headers_Binding::GetConstructorObject(cx); + Request_Binding::CreateAndDefineOnGlobal(cx) && + Response_Binding::CreateAndDefineOnGlobal(cx) && + Headers_Binding::CreateAndDefineOnGlobal(cx); } static bool SandboxCreateStorage(JSContext* cx, JS::HandleObject obj) { @@ -363,6 +364,10 @@ static bool SandboxCreateStorage(JSContext* cx, JS::HandleObject obj) { nsIGlobalObject* native = xpc::NativeGlobal(obj); MOZ_ASSERT(native); + if (!StorageManager_Binding::CreateAndDefineOnGlobal(cx)) { + return false; + } + dom::StorageManager* storageManager = new dom::StorageManager(native); JS::RootedObject wrapped(cx, storageManager->WrapObject(cx, nullptr)); return JS_DefineProperty(cx, obj, "storage", wrapped, JSPROP_ENUMERATE); @@ -1027,151 +1032,62 @@ bool xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj) { // This function holds common properties not exposed automatically but able // to be requested either in |Cu.importGlobalProperties| or // |wantGlobalProperties| of a sandbox. - if (AbortController && - !dom::AbortController_Binding::GetConstructorObject(cx)) { - return false; + +#define DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(_iface) \ + if ((_iface) && !dom::_iface##_Binding::CreateAndDefineOnGlobal(cx)) { \ + return false; \ } - if (Blob && !dom::Blob_Binding::GetConstructorObject(cx)) return false; - - if (ChromeUtils && !dom::ChromeUtils_Binding::GetConstructorObject(cx)) { + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(AbortController) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(ChromeUtils) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Blob) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(CSS) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(CSSRule) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(CustomStateSet) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Directory) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Document) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(DOMException) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(DOMParser) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(DOMTokenList) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Element) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Event) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(File) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(FileReader) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(FormData) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Headers) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(IOUtils) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(InspectorCSSParser) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(InspectorUtils) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(MessageChannel) + if (MessageChannel && !MessagePort_Binding::CreateAndDefineOnGlobal(cx)) { return false; } + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(MIDIInputMap) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(MIDIOutputMap) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Node) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(NodeFilter) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(PathUtils) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Performance) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(PromiseDebugging) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Range) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(ReadableStream) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Selection) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(TextDecoder) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(TextEncoder) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(URL) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(URLSearchParams) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(WebSocket) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(Window) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(XMLHttpRequest) + DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE(XMLSerializer) - if (CSS && !dom::CSS_Binding::GetConstructorObject(cx)) { - return false; - } - - if (CSSRule && !dom::CSSRule_Binding::GetConstructorObject(cx)) { - return false; - } - - if (CustomStateSet && - !dom::CustomStateSet_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Directory && !dom::Directory_Binding::GetConstructorObject(cx)) - return false; - - if (Document && !dom::Document_Binding::GetConstructorObject(cx)) { - return false; - } - - if (DOMException && !dom::DOMException_Binding::GetConstructorObject(cx)) { - return false; - } - - if (DOMParser && !dom::DOMParser_Binding::GetConstructorObject(cx)) { - return false; - } - - if (DOMTokenList && !dom::DOMTokenList_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Element && !dom::Element_Binding::GetConstructorObject(cx)) return false; - - if (Event && !dom::Event_Binding::GetConstructorObject(cx)) return false; - - if (File && !dom::File_Binding::GetConstructorObject(cx)) return false; - - if (FileReader && !dom::FileReader_Binding::GetConstructorObject(cx)) { - return false; - } - - if (FormData && !dom::FormData_Binding::GetConstructorObject(cx)) - return false; - - if (Headers && !dom::Headers_Binding::GetConstructorObject(cx)) { - return false; - } - - if (IOUtils && !dom::IOUtils_Binding::GetConstructorObject(cx)) { - return false; - } - - if (InspectorCSSParser && - !dom::InspectorCSSParser_Binding::GetConstructorObject(cx)) { - return false; - } - - if (InspectorUtils && !dom::InspectorUtils_Binding::GetConstructorObject(cx)) - return false; - - if (MessageChannel && - (!dom::MessageChannel_Binding::GetConstructorObject(cx) || - !dom::MessagePort_Binding::GetConstructorObject(cx))) - return false; - - if (MIDIInputMap && !dom::MIDIInputMap_Binding::GetConstructorObject(cx)) { - return false; - } - - if (MIDIOutputMap && !dom::MIDIOutputMap_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Node && !dom::Node_Binding::GetConstructorObject(cx)) { - return false; - } - - if (NodeFilter && !dom::NodeFilter_Binding::GetConstructorObject(cx)) { - return false; - } - - if (PathUtils && !dom::PathUtils_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Performance && !dom::Performance_Binding::GetConstructorObject(cx)) { - return false; - } - - if (PromiseDebugging && - !dom::PromiseDebugging_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Range && !dom::Range_Binding::GetConstructorObject(cx)) { - return false; - } - - if (Selection && !dom::Selection_Binding::GetConstructorObject(cx)) { - return false; - } - - if (TextDecoder && !dom::TextDecoder_Binding::GetConstructorObject(cx)) - return false; - - if (TextEncoder && !dom::TextEncoder_Binding::GetConstructorObject(cx)) - return false; - - if (URL && !dom::URL_Binding::GetConstructorObject(cx)) return false; - - if (URLSearchParams && - !dom::URLSearchParams_Binding::GetConstructorObject(cx)) - return false; - - if (XMLHttpRequest && !dom::XMLHttpRequest_Binding::GetConstructorObject(cx)) - return false; - - if (WebSocket && !dom::WebSocket_Binding::GetConstructorObject(cx)) - return false; - - if (Window && !dom::Window_Binding::GetConstructorObject(cx)) return false; - - if (XMLSerializer && !dom::XMLSerializer_Binding::GetConstructorObject(cx)) - return false; - - if (ReadableStream && !dom::ReadableStream_Binding::GetConstructorObject(cx)) - return false; +#undef DEFINE_WEBIDL_INTERFACE_OR_NAMESPACE if (atob && !JS_DefineFunction(cx, obj, "atob", Atob, 1, 0)) return false; if (btoa && !JS_DefineFunction(cx, obj, "btoa", Btoa, 1, 0)) return false; - if (caches && !dom::cache::CacheStorage::DefineCaches(cx, obj)) { + if (caches && !dom::cache::CacheStorage::DefineCachesForSandbox(cx, obj)) { return false; }