WebKit Bugzilla
Attachment 369889 Details for
Bug 197751
: [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197751-20190514135752.patch (text/plain), 50.15 KB, created by
Andy Estes
on 2019-05-14 13:57:53 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Andy Estes
Created:
2019-05-14 13:57:53 PDT
Size:
50.15 KB
patch
obsolete
>Subversion Revision: 245157 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 92d9cea312f7541aeadd0c4b1956a9069b665df0..e1cb6d0a89d8535159aa8255523d30dec068bcea 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,57 @@ >+2019-05-09 Andy Estes <aestes@apple.com> >+ >+ [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts >+ https://bugs.webkit.org/show_bug.cgi?id=197751 >+ <rdar://problem/50631563> >+ >+ Reviewed by Alex Christensen. >+ >+ In r243324, when a document has had user agent scripts injected into it, payment APIs were >+ disabled at runtime by having all entry points return falsy values or throw exceptions >+ (e.g., ApplePaySession.canMakePayments() returns false). >+ >+ In the case of user scripts in particular (e.g., WKUserScript), since we know whether these >+ exist at the time we create a document's DOMWindow, we can do better than r243324 by >+ completely disabling the payment APIs in the presence of user scripts. >+ >+ To achieve this, this change introduces the 'EnabledByContext' extended attribute for >+ interfaces, which instructs the bindings generator to add a conjunct to the payment API >+ constructors that asks the interface's implementation class whether it should be enabled for >+ a given ScriptExecutionContext. The PaymentRequest and ApplePaySession interfaces adopt this >+ new extended attribute to implement the new user script check. >+ >+ Added new API tests. >+ >+ * Modules/applepay/ApplePaySession.idl: >+ * Modules/applepay/PaymentCoordinator.cpp: >+ (WebCore::PaymentCoordinator::shouldEnableApplePayAPIs const): >+ * Modules/applepay/PaymentCoordinator.h: >+ * Modules/applepay/PaymentSession.cpp: >+ (WebCore::PaymentSession::enabledForContext): >+ * Modules/applepay/PaymentSession.h: >+ * Modules/paymentrequest/PaymentHandler.cpp: >+ (WebCore::PaymentHandler::enabledForContext): >+ * Modules/paymentrequest/PaymentHandler.h: >+ * Modules/paymentrequest/PaymentRequest.cpp: >+ (WebCore::PaymentRequest::enabledForContext): >+ * Modules/paymentrequest/PaymentRequest.h: >+ * Modules/paymentrequest/PaymentRequest.idl: >+ * bindings/scripts/CodeGeneratorJS.pm: >+ (NeedsRuntimeCheck): >+ (GenerateRuntimeEnableConditionalString): >+ * bindings/scripts/IDLAttributes.json: >+ * bindings/scripts/preprocess-idls.pl: >+ (GenerateConstructorAttributes): >+ * bindings/scripts/test/JS/JSTestEnabledForContext.cpp: Added. >+ * bindings/scripts/test/JS/JSTestEnabledForContext.h: Added. >+ * bindings/scripts/test/JS/JSTestGlobalObject.cpp: >+ (WebCore::JSTestGlobalObject::finishCreation): >+ (WebCore::jsTestGlobalObjectTestEnabledForContextConstructorGetter): >+ (WebCore::jsTestGlobalObjectTestEnabledForContextConstructor): >+ (WebCore::setJSTestGlobalObjectTestEnabledForContextConstructorSetter): >+ (WebCore::setJSTestGlobalObjectTestEnabledForContextConstructor): >+ * bindings/scripts/test/TestEnabledForContext.idl: Added. >+ > 2019-05-09 Eric Carlson <eric.carlson@apple.com> > > Refine AudioSession route sharing policy >diff --git a/Source/WebCore/Modules/applepay/ApplePaySession.idl b/Source/WebCore/Modules/applepay/ApplePaySession.idl >index 66a89f89b39c94e49380df5abe693a0082fdd005..0850bd5b60502e6bf85c0ee6bcc705f690593909 100644 >--- a/Source/WebCore/Modules/applepay/ApplePaySession.idl >+++ b/Source/WebCore/Modules/applepay/ApplePaySession.idl >@@ -30,6 +30,7 @@ > ConstructorCallWith=Document, > ConstructorMayThrowException, > EnabledBySetting=ApplePay, >+ EnabledForContext, > ] interface ApplePaySession : EventTarget { > const unsigned short STATUS_SUCCESS = 0; > const unsigned short STATUS_FAILURE = 1; >diff --git a/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp b/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp >index 524f436598c22845fa53c716649e75468c36cf0a..d559948d0a6faa63e205ba09fcf192b1b0bb02c7 100644 >--- a/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp >+++ b/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp >@@ -31,9 +31,11 @@ > #include "Document.h" > #include "LinkIconCollector.h" > #include "Logging.h" >+#include "Page.h" > #include "PaymentAuthorizationStatus.h" > #include "PaymentCoordinatorClient.h" > #include "PaymentSession.h" >+#include "UserContentProvider.h" > #include <wtf/CompletionHandler.h> > #include <wtf/URL.h> > >@@ -251,6 +253,22 @@ Optional<String> PaymentCoordinator::validatedPaymentNetwork(Document& document, > return m_client.validatedPaymentNetwork(paymentNetwork); > } > >+bool PaymentCoordinator::shouldEnableApplePayAPIs(Document& document) const >+{ >+ if (m_client.supportsUnrestrictedApplePay()) { >+ RELEASE_LOG_IF_ALLOWED("shouldEnableApplePayAPIs() -> true (unrestricted client)"); >+ return true; >+ } >+ >+ bool shouldEnableAPIs = true; >+ document.page()->userContentProvider().forEachUserScript([&](DOMWrapperWorld&, const UserScript&) { >+ shouldEnableAPIs = false; >+ }); >+ >+ RELEASE_LOG_IF_ALLOWED("shouldEnableApplePayAPIs() -> %d", shouldEnableAPIs); >+ return shouldEnableAPIs; >+} >+ > bool PaymentCoordinator::shouldAllowApplePay(Document& document) const > { > if (m_client.supportsUnrestrictedApplePay()) { >diff --git a/Source/WebCore/Modules/applepay/PaymentCoordinator.h b/Source/WebCore/Modules/applepay/PaymentCoordinator.h >index 3b321a218550d094dcfd11ccb694eaa455c950f9..260a3e2811626e7e48dcb00c22e0763c9b2a6e98 100644 >--- a/Source/WebCore/Modules/applepay/PaymentCoordinator.h >+++ b/Source/WebCore/Modules/applepay/PaymentCoordinator.h >@@ -78,6 +78,7 @@ public: > > Optional<String> validatedPaymentNetwork(Document&, unsigned version, const String&) const; > >+ bool shouldEnableApplePayAPIs(Document&) const; > WEBCORE_EXPORT bool shouldAllowApplePay(Document&) const; > WEBCORE_EXPORT bool shouldAllowUserAgentScripts(Document&) const; > >diff --git a/Source/WebCore/Modules/applepay/PaymentSession.cpp b/Source/WebCore/Modules/applepay/PaymentSession.cpp >index 87a44f4b35bb2fb4293e304f27f06b6e6eba1949..65d9f869b08c81946569c79777877f8caa435ae2 100644 >--- a/Source/WebCore/Modules/applepay/PaymentSession.cpp >+++ b/Source/WebCore/Modules/applepay/PaymentSession.cpp >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -30,6 +30,7 @@ > > #include "Document.h" > #include "DocumentLoader.h" >+#include "Page.h" > #include "SecurityOrigin.h" > > namespace WebCore { >@@ -72,6 +73,15 @@ ExceptionOr<void> PaymentSession::canCreateSession(Document& document) > return { }; > } > >+bool PaymentSession::enabledForContext(ScriptExecutionContext& context) >+{ >+ auto& document = downcast<Document>(context); >+ if (auto page = document.page()) >+ return page->paymentCoordinator().shouldEnableApplePayAPIs(document); >+ >+ return false; >+} >+ > } // namespace WebCore > > #endif // ENABLE(APPLE_PAY) >diff --git a/Source/WebCore/Modules/applepay/PaymentSession.h b/Source/WebCore/Modules/applepay/PaymentSession.h >index 8f7a4b650f0b92f815f9b5d5cce179a7d5291043..3222f59e0906133ec4c48773e0178543ff71a6c9 100644 >--- a/Source/WebCore/Modules/applepay/PaymentSession.h >+++ b/Source/WebCore/Modules/applepay/PaymentSession.h >@@ -41,6 +41,7 @@ class PaymentMethod; > class PaymentSession : public virtual PaymentSessionBase { > public: > static ExceptionOr<void> canCreateSession(Document&); >+ static bool enabledForContext(ScriptExecutionContext&); > > virtual unsigned version() const = 0; > virtual void validateMerchant(URL&&) = 0; >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp b/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp >index 0488eaeb66fb50c9b485030eaf3d4d1029aea018..a76d4b4b9bdba79c4e261ad5b16139ce7f2bd624 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp >+++ b/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -61,6 +61,16 @@ ExceptionOr<void> PaymentHandler::canCreateSession(Document& document) > return { }; > } > >+bool PaymentHandler::enabledForContext(ScriptExecutionContext& context) >+{ >+#if ENABLE(APPLE_PAY) >+ return PaymentSession::enabledForContext(context); >+#else >+ UNUSED_PARAM(context); >+ return false; >+#endif >+} >+ > bool PaymentHandler::hasActiveSession(Document& document) > { > #if ENABLE(APPLE_PAY) >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentHandler.h b/Source/WebCore/Modules/paymentrequest/PaymentHandler.h >index 0b4df03bb67b47a3db1e5a78624d294a74070afa..b48ba733bb0a0d47c67c6c94815968872a1970fb 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentHandler.h >+++ b/Source/WebCore/Modules/paymentrequest/PaymentHandler.h >@@ -46,6 +46,7 @@ class PaymentHandler : public virtual PaymentSessionBase { > public: > static RefPtr<PaymentHandler> create(Document&, PaymentRequest&, const PaymentRequest::MethodIdentifier&); > static ExceptionOr<void> canCreateSession(Document&); >+ static bool enabledForContext(ScriptExecutionContext&); > static bool hasActiveSession(Document&); > > virtual ExceptionOr<void> convertData(JSC::JSValue&&) = 0; >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp b/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >index 61ff5be21caae7ede99866afc029fcddd082cb98..d2ef7a61ed510b06a32c052fc70903655b39e00a 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >+++ b/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >@@ -34,7 +34,9 @@ > #include "JSDOMPromise.h" > #include "JSPaymentDetailsUpdate.h" > #include "JSPaymentResponse.h" >+#include "Page.h" > #include "PaymentAddress.h" >+#include "PaymentCoordinator.h" > #include "PaymentCurrencyAmount.h" > #include "PaymentDetailsInit.h" > #include "PaymentHandler.h" >@@ -351,6 +353,11 @@ ExceptionOr<Ref<PaymentRequest>> PaymentRequest::create(Document& document, Vect > return adoptRef(*new PaymentRequest(document, WTFMove(options), WTFMove(details), WTFMove(std::get<1>(shippingOptionAndModifierData)), WTFMove(serializedMethodData), WTFMove(std::get<0>(shippingOptionAndModifierData)))); > } > >+bool PaymentRequest::enabledForContext(ScriptExecutionContext& context) >+{ >+ return PaymentHandler::enabledForContext(context); >+} >+ > PaymentRequest::PaymentRequest(Document& document, PaymentOptions&& options, PaymentDetailsInit&& details, Vector<String>&& serializedModifierData, Vector<Method>&& serializedMethodData, String&& selectedShippingOption) > : ActiveDOMObject { document } > , m_options { WTFMove(options) } >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentRequest.h b/Source/WebCore/Modules/paymentrequest/PaymentRequest.h >index cc0bbcb5f4c84c9fbd7d8f384b965bbfab527cdf..f7c3426794451b5befda07bb95d3576441aded8b 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentRequest.h >+++ b/Source/WebCore/Modules/paymentrequest/PaymentRequest.h >@@ -58,6 +58,7 @@ public: > using ShowPromise = DOMPromiseDeferred<IDLInterface<PaymentResponse>>; > > static ExceptionOr<Ref<PaymentRequest>> create(Document&, Vector<PaymentMethodData>&&, PaymentDetailsInit&&, PaymentOptions&&); >+ static bool enabledForContext(ScriptExecutionContext&); > ~PaymentRequest(); > > void show(Document&, RefPtr<DOMPromise>&& detailsPromise, ShowPromise&&); >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl b/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl >index b9c1264cca487174fff4d55d3c78d322526b99f0..918c1083f4bc6ad7c19926454f40719a746ab6ac 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl >+++ b/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl >@@ -30,6 +30,7 @@ > ConstructorCallWith=Document, > ConstructorMayThrowException, > EnabledBySetting=PaymentRequest, >+ EnabledForContext, > SecureContext, > ] interface PaymentRequest : EventTarget { > [CallWith=Document] Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise); >diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >index 505c4f2ef141b35682a174475dec226af9d71dcc..f309a4b7c7edabf0e6109a38300d138ec3d0d0ee 100644 >--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >@@ -1705,6 +1705,7 @@ sub NeedsRuntimeCheck > } > > return $context->extendedAttributes->{EnabledAtRuntime} >+ || $context->extendedAttributes->{EnabledForContext} > || $context->extendedAttributes->{EnabledForWorld} > || $context->extendedAttributes->{EnabledBySetting} > || $context->extendedAttributes->{DisabledByQuirk} >@@ -3788,6 +3789,15 @@ sub GenerateRuntimeEnableConditionalString > } > } > >+ if ($context->extendedAttributes->{EnabledForContext}) { >+ assert("Must not specify value for EnabledForContext.") unless $context->extendedAttributes->{EnabledForContext} eq "VALUE_IS_MISSING"; >+ assert("EnabledForContext must be an interface or constructor attribute.") unless $codeGenerator->IsConstructorType($context->type); >+ >+ my $contextRef = "*jsCast<JSDOMGlobalObject*>(" . $globalObjectPtr . ")->scriptExecutionContext()"; >+ my $name = $context->name; >+ push(@conjuncts, "${name}::enabledForContext(" . $contextRef . ")"); >+ } >+ > my $result = join(" && ", @conjuncts); > $result = "($result)" if @conjuncts > 1; > return $result; >diff --git a/Source/WebCore/bindings/scripts/IDLAttributes.json b/Source/WebCore/bindings/scripts/IDLAttributes.json >index efe5697948594eca5dc91f1dd2d1129b68b5ad15..469fd2df9ee6f2769ae89b40580f5caba7b8ce37 100644 >--- a/Source/WebCore/bindings/scripts/IDLAttributes.json >+++ b/Source/WebCore/bindings/scripts/IDLAttributes.json >@@ -192,6 +192,9 @@ > "contextsAllowed": ["interface", "dictionary", "enum", "attribute", "operation", "constant"], > "values": ["*"] > }, >+ "EnabledForContext": { >+ "contextsAllowed": ["attribute", "interface"] >+ }, > "EnabledForWorld": { > "contextsAllowed": ["attribute", "operation"], > "values": ["*"] >diff --git a/Source/WebCore/bindings/scripts/preprocess-idls.pl b/Source/WebCore/bindings/scripts/preprocess-idls.pl >index 1ac8fed6a86bc4413be21ad89286af65fbe005b8..97721303f8a9ae229df63c44e58fcd934c2c7c37 100644 >--- a/Source/WebCore/bindings/scripts/preprocess-idls.pl >+++ b/Source/WebCore/bindings/scripts/preprocess-idls.pl >@@ -283,7 +283,7 @@ sub GenerateConstructorAttributes > foreach my $attributeName (sort keys %{$extendedAttributes}) { > next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledForWorld" > || $attributeName eq "EnabledBySetting" || $attributeName eq "SecureContext" || $attributeName eq "PrivateIdentifier" >- || $attributeName eq "PublicIdentifier" || $attributeName eq "DisabledByQuirk" || $attributeName eq "EnabledByQuirk"); >+ || $attributeName eq "PublicIdentifier" || $attributeName eq "DisabledByQuirk" || $attributeName eq "EnabledByQuirk" || $attributeName eq "EnabledForContext"); > my $extendedAttribute = $attributeName; > $extendedAttribute .= "=" . $extendedAttributes->{$attributeName} unless $extendedAttributes->{$attributeName} eq "VALUE_IS_MISSING"; > push(@extendedAttributesList, $extendedAttribute); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..9b7fb7d256f5975c12b2d420ded36e64cd720a33 >--- /dev/null >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp >@@ -0,0 +1,267 @@ >+/* >+ This file is part of the WebKit open source project. >+ This file has been generated by generate-bindings.pl. DO NOT MODIFY! >+ >+ This library is free software; you can redistribute it and/or >+ modify it under the terms of the GNU Library General Public >+ License as published by the Free Software Foundation; either >+ version 2 of the License, or (at your option) any later version. >+ >+ This library is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ Library General Public License for more details. >+ >+ You should have received a copy of the GNU Library General Public License >+ along with this library; see the file COPYING.LIB. If not, write to >+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ Boston, MA 02110-1301, USA. >+*/ >+ >+#include "config.h" >+#include "JSTestEnabledForContext.h" >+ >+#include "Document.h" >+#include "JSDOMAttribute.h" >+#include "JSDOMBinding.h" >+#include "JSDOMConstructorNotConstructable.h" >+#include "JSDOMExceptionHandling.h" >+#include "JSDOMWrapperCache.h" >+#include "JSTestSubObj.h" >+#include "ScriptExecutionContext.h" >+#include "Settings.h" >+#include "WebCoreJSClientData.h" >+#include <JavaScriptCore/FunctionPrototype.h> >+#include <JavaScriptCore/HeapSnapshotBuilder.h> >+#include <JavaScriptCore/JSCInlines.h> >+#include <wtf/GetPtr.h> >+#include <wtf/PointerPreparations.h> >+#include <wtf/URL.h> >+ >+ >+namespace WebCore { >+using namespace JSC; >+ >+// Attributes >+ >+JSC::EncodedJSValue jsTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); >+bool setJSTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); >+JSC::EncodedJSValue jsTestEnabledForContextTestSubObjEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); >+bool setJSTestEnabledForContextTestSubObjEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); >+ >+class JSTestEnabledForContextPrototype : public JSC::JSNonFinalObject { >+public: >+ using Base = JSC::JSNonFinalObject; >+ static JSTestEnabledForContextPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure) >+ { >+ JSTestEnabledForContextPrototype* ptr = new (NotNull, JSC::allocateCell<JSTestEnabledForContextPrototype>(vm.heap)) JSTestEnabledForContextPrototype(vm, globalObject, structure); >+ ptr->finishCreation(vm); >+ return ptr; >+ } >+ >+ DECLARE_INFO; >+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) >+ { >+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); >+ } >+ >+private: >+ JSTestEnabledForContextPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) >+ : JSC::JSNonFinalObject(vm, structure) >+ { >+ } >+ >+ void finishCreation(JSC::VM&); >+}; >+ >+using JSTestEnabledForContextConstructor = JSDOMConstructorNotConstructable<JSTestEnabledForContext>; >+ >+template<> JSValue JSTestEnabledForContextConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject) >+{ >+ UNUSED_PARAM(vm); >+ return globalObject.functionPrototype(); >+} >+ >+template<> void JSTestEnabledForContextConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject) >+{ >+ putDirect(vm, vm.propertyNames->prototype, JSTestEnabledForContext::prototype(vm, globalObject), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); >+ putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String("TestEnabledForContext"_s)), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); >+ putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); >+} >+ >+template<> const ClassInfo JSTestEnabledForContextConstructor::s_info = { "TestEnabledForContext", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTestEnabledForContextConstructor) }; >+ >+/* Hash table for prototype */ >+ >+static const HashTableValue JSTestEnabledForContextPrototypeTableValues[] = >+{ >+ { "constructor", static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEnabledForContextConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestEnabledForContextConstructor) } }, >+}; >+ >+const ClassInfo JSTestEnabledForContextPrototype::s_info = { "TestEnabledForContextPrototype", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTestEnabledForContextPrototype) }; >+ >+void JSTestEnabledForContextPrototype::finishCreation(VM& vm) >+{ >+ Base::finishCreation(vm); >+ reifyStaticProperties(vm, JSTestEnabledForContext::info(), JSTestEnabledForContextPrototypeTableValues, *this); >+} >+ >+const ClassInfo JSTestEnabledForContext::s_info = { "TestEnabledForContext", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTestEnabledForContext) }; >+ >+JSTestEnabledForContext::JSTestEnabledForContext(Structure* structure, JSDOMGlobalObject& globalObject, Ref<TestEnabledForContext>&& impl) >+ : JSDOMWrapper<TestEnabledForContext>(structure, globalObject, WTFMove(impl)) >+{ >+} >+ >+void JSTestEnabledForContext::finishCreation(VM& vm) >+{ >+ Base::finishCreation(vm); >+ ASSERT(inherits(vm, info())); >+ >+ if ((downcast<Document>(jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext())->settings().testSettingEnabled() && TestSubObjEnabledForContext::enabledForContext(*jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()))) >+ putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().TestSubObjEnabledForContextPublicName(), CustomGetterSetter::create(vm, jsTestEnabledForContextTestSubObjEnabledForContextConstructor, setJSTestEnabledForContextTestSubObjEnabledForContextConstructor), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); >+} >+ >+JSObject* JSTestEnabledForContext::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) >+{ >+ return JSTestEnabledForContextPrototype::create(vm, &globalObject, JSTestEnabledForContextPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype())); >+} >+ >+JSObject* JSTestEnabledForContext::prototype(VM& vm, JSDOMGlobalObject& globalObject) >+{ >+ return getDOMPrototype<JSTestEnabledForContext>(vm, globalObject); >+} >+ >+JSValue JSTestEnabledForContext::getConstructor(VM& vm, const JSGlobalObject* globalObject) >+{ >+ return getDOMConstructor<JSTestEnabledForContextConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject)); >+} >+ >+void JSTestEnabledForContext::destroy(JSC::JSCell* cell) >+{ >+ JSTestEnabledForContext* thisObject = static_cast<JSTestEnabledForContext*>(cell); >+ thisObject->JSTestEnabledForContext::~JSTestEnabledForContext(); >+} >+ >+template<> inline JSTestEnabledForContext* IDLAttribute<JSTestEnabledForContext>::cast(ExecState& state, EncodedJSValue thisValue) >+{ >+ return jsDynamicCast<JSTestEnabledForContext*>(state.vm(), JSValue::decode(thisValue)); >+} >+ >+EncodedJSValue jsTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName) >+{ >+ VM& vm = state->vm(); >+ auto throwScope = DECLARE_THROW_SCOPE(vm); >+ auto* prototype = jsDynamicCast<JSTestEnabledForContextPrototype*>(vm, JSValue::decode(thisValue)); >+ if (UNLIKELY(!prototype)) >+ return throwVMTypeError(state, throwScope); >+ return JSValue::encode(JSTestEnabledForContext::getConstructor(state->vm(), prototype->globalObject())); >+} >+ >+bool setJSTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue) >+{ >+ VM& vm = state->vm(); >+ auto throwScope = DECLARE_THROW_SCOPE(vm); >+ auto* prototype = jsDynamicCast<JSTestEnabledForContextPrototype*>(vm, JSValue::decode(thisValue)); >+ if (UNLIKELY(!prototype)) { >+ throwVMTypeError(state, throwScope); >+ return false; >+ } >+ // Shadowing a built-in constructor >+ return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue)); >+} >+ >+static inline JSValue jsTestEnabledForContextTestSubObjEnabledForContextConstructorGetter(ExecState& state, JSTestEnabledForContext& thisObject, ThrowScope& throwScope) >+{ >+ UNUSED_PARAM(throwScope); >+ UNUSED_PARAM(state); >+ return JSTestSubObj::getConstructor(state.vm(), thisObject.globalObject()); >+} >+ >+EncodedJSValue jsTestEnabledForContextTestSubObjEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName) >+{ >+ return IDLAttribute<JSTestEnabledForContext>::get<jsTestEnabledForContextTestSubObjEnabledForContextConstructorGetter>(*state, thisValue, "TestSubObjEnabledForContext"); >+} >+ >+static inline bool setJSTestEnabledForContextTestSubObjEnabledForContextConstructorSetter(ExecState& state, JSTestEnabledForContext& thisObject, JSValue value, ThrowScope& throwScope) >+{ >+ UNUSED_PARAM(throwScope); >+ // Shadowing a built-in constructor. >+ return thisObject.putDirect(state.vm(), Identifier::fromString(&state.vm(), reinterpret_cast<const LChar*>("TestSubObjEnabledForContext"), strlen("TestSubObjEnabledForContext")), value); >+} >+ >+bool setJSTestEnabledForContextTestSubObjEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue) >+{ >+ return IDLAttribute<JSTestEnabledForContext>::set<setJSTestEnabledForContextTestSubObjEnabledForContextConstructorSetter>(*state, thisValue, encodedValue, "TestSubObjEnabledForContext"); >+} >+ >+void JSTestEnabledForContext::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestEnabledForContext*>(cell); >+ builder.setWrappedObjectForCell(cell, &thisObject->wrapped()); >+ if (thisObject->scriptExecutionContext()) >+ builder.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string()); >+ Base::heapSnapshot(cell, builder); >+} >+ >+bool JSTestEnabledForContextOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) >+{ >+ UNUSED_PARAM(handle); >+ UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); >+ return false; >+} >+ >+void JSTestEnabledForContextOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) >+{ >+ auto* jsTestEnabledForContext = static_cast<JSTestEnabledForContext*>(handle.slot()->asCell()); >+ auto& world = *static_cast<DOMWrapperWorld*>(context); >+ uncacheWrapper(world, &jsTestEnabledForContext->wrapped(), jsTestEnabledForContext); >+} >+ >+#if ENABLE(BINDING_INTEGRITY) >+#if PLATFORM(WIN) >+#pragma warning(disable: 4483) >+extern "C" { extern void (*const __identifier("??_7TestEnabledForContext@WebCore@@6B@")[])(); } >+#else >+extern "C" { extern void* _ZTVN7WebCore21TestEnabledForContextE[]; } >+#endif >+#endif >+ >+JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<TestEnabledForContext>&& impl) >+{ >+ >+#if ENABLE(BINDING_INTEGRITY) >+ void* actualVTablePointer = *(reinterpret_cast<void**>(impl.ptr())); >+#if PLATFORM(WIN) >+ void* expectedVTablePointer = WTF_PREPARE_VTBL_POINTER_FOR_INSPECTION(__identifier("??_7TestEnabledForContext@WebCore@@6B@")); >+#else >+ void* expectedVTablePointer = WTF_PREPARE_VTBL_POINTER_FOR_INSPECTION(&_ZTVN7WebCore21TestEnabledForContextE[2]); >+#endif >+ >+ // If this fails TestEnabledForContext does not have a vtable, so you need to add the >+ // ImplementationLacksVTable attribute to the interface definition >+ static_assert(std::is_polymorphic<TestEnabledForContext>::value, "TestEnabledForContext is not polymorphic"); >+ >+ // If you hit this assertion you either have a use after free bug, or >+ // TestEnabledForContext has subclasses. If TestEnabledForContext has subclasses that get passed >+ // to toJS() we currently require TestEnabledForContext you to opt out of binding hardening >+ // by adding the SkipVTableValidation attribute to the interface IDL definition >+ RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer); >+#endif >+ return createWrapper<TestEnabledForContext>(globalObject, WTFMove(impl)); >+} >+ >+JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, TestEnabledForContext& impl) >+{ >+ return wrap(state, globalObject, impl); >+} >+ >+TestEnabledForContext* JSTestEnabledForContext::toWrapped(JSC::VM& vm, JSC::JSValue value) >+{ >+ if (auto* wrapper = jsDynamicCast<JSTestEnabledForContext*>(vm, value)) >+ return &wrapper->wrapped(); >+ return nullptr; >+} >+ >+} >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h >new file mode 100644 >index 0000000000000000000000000000000000000000..b6387d4236132247f2d7c499ff4a0f956ec06ad6 >--- /dev/null >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h >@@ -0,0 +1,88 @@ >+/* >+ This file is part of the WebKit open source project. >+ This file has been generated by generate-bindings.pl. DO NOT MODIFY! >+ >+ This library is free software; you can redistribute it and/or >+ modify it under the terms of the GNU Library General Public >+ License as published by the Free Software Foundation; either >+ version 2 of the License, or (at your option) any later version. >+ >+ This library is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ Library General Public License for more details. >+ >+ You should have received a copy of the GNU Library General Public License >+ along with this library; see the file COPYING.LIB. If not, write to >+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ Boston, MA 02110-1301, USA. >+*/ >+ >+#pragma once >+ >+#include "JSDOMWrapper.h" >+#include "TestEnabledForContext.h" >+#include <wtf/NeverDestroyed.h> >+ >+namespace WebCore { >+ >+class JSTestEnabledForContext : public JSDOMWrapper<TestEnabledForContext> { >+public: >+ using Base = JSDOMWrapper<TestEnabledForContext>; >+ static JSTestEnabledForContext* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<TestEnabledForContext>&& impl) >+ { >+ JSTestEnabledForContext* ptr = new (NotNull, JSC::allocateCell<JSTestEnabledForContext>(globalObject->vm().heap)) JSTestEnabledForContext(structure, *globalObject, WTFMove(impl)); >+ ptr->finishCreation(globalObject->vm()); >+ return ptr; >+ } >+ >+ static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&); >+ static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&); >+ static TestEnabledForContext* toWrapped(JSC::VM&, JSC::JSValue); >+ static void destroy(JSC::JSCell*); >+ >+ DECLARE_INFO; >+ >+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) >+ { >+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); >+ } >+ >+ static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); >+public: >+ static const unsigned StructureFlags = Base::StructureFlags | JSC::HasStaticPropertyTable; >+protected: >+ JSTestEnabledForContext(JSC::Structure*, JSDOMGlobalObject&, Ref<TestEnabledForContext>&&); >+ >+ void finishCreation(JSC::VM&); >+}; >+ >+class JSTestEnabledForContextOwner : public JSC::WeakHandleOwner { >+public: >+ virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**); >+ virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); >+}; >+ >+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, TestEnabledForContext*) >+{ >+ static NeverDestroyed<JSTestEnabledForContextOwner> owner; >+ return &owner.get(); >+} >+ >+inline void* wrapperKey(TestEnabledForContext* wrappableObject) >+{ >+ return wrappableObject; >+} >+ >+JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, TestEnabledForContext&); >+inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, TestEnabledForContext* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); } >+JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, Ref<TestEnabledForContext>&&); >+inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* state, JSDOMGlobalObject* globalObject, RefPtr<TestEnabledForContext>&& impl) { return impl ? toJSNewlyCreated(state, globalObject, impl.releaseNonNull()) : JSC::jsNull(); } >+ >+template<> struct JSDOMWrapperConverterTraits<TestEnabledForContext> { >+ using WrapperClass = JSTestEnabledForContext; >+ using ToWrappedReturnType = TestEnabledForContext*; >+}; >+ >+} // namespace WebCore >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >index 35d16ee0f734871b3937e9f3e4ef6d95289bc8b8..b8914f986783d3f98499ddad5aa4e45ca9555b3d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >@@ -39,6 +39,7 @@ > #include "JSTestDOMJIT.h" > #include "JSTestDomainSecurity.h" > #include "JSTestEnabledBySetting.h" >+#include "JSTestEnabledForContext.h" > #include "JSTestEventConstructor.h" > #include "JSTestEventTarget.h" > #include "JSTestException.h" >@@ -172,6 +173,8 @@ JSC::EncodedJSValue jsTestGlobalObjectTestDomainSecurityConstructor(JSC::ExecSta > bool setJSTestGlobalObjectTestDomainSecurityConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); > JSC::EncodedJSValue jsTestGlobalObjectTestEnabledBySettingConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); > bool setJSTestGlobalObjectTestEnabledBySettingConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); >+JSC::EncodedJSValue jsTestGlobalObjectTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); >+bool setJSTestGlobalObjectTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); > JSC::EncodedJSValue jsTestGlobalObjectTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); > bool setJSTestGlobalObjectTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue); > JSC::EncodedJSValue jsTestGlobalObjectTestEventTargetConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); >@@ -702,6 +705,8 @@ void JSTestGlobalObject::finishCreation(VM& vm) > if (RuntimeEnabledFeatures::sharedFeatures().testFeatureEnabled()) > putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().enabledAtRuntimeAttributePublicName(), CustomGetterSetter::create(vm, jsTestGlobalObjectEnabledAtRuntimeAttribute, setJSTestGlobalObjectEnabledAtRuntimeAttribute), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor))); > #endif >+ if ((jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext() && TestEnabledForContext::enabledForContext(*jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()))) >+ putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().TestEnabledForContextPublicName(), CustomGetterSetter::create(vm, jsTestGlobalObjectTestEnabledForContextConstructor, setJSTestGlobalObjectTestEnabledForContextConstructor), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); > putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().publicAndPrivateAttributePrivateName(), CustomGetterSetter::create(vm, jsTestGlobalObjectPublicAndPrivateAttribute, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); > #if ENABLE(TEST_FEATURE) > putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().publicAndPrivateConditionalAttributePrivateName(), CustomGetterSetter::create(vm, jsTestGlobalObjectPublicAndPrivateConditionalAttribute, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); >@@ -1116,6 +1121,30 @@ bool setJSTestGlobalObjectTestEnabledBySettingConstructor(ExecState* state, Enco > return IDLAttribute<JSTestGlobalObject>::set<setJSTestGlobalObjectTestEnabledBySettingConstructorSetter>(*state, thisValue, encodedValue, "TestEnabledBySetting"); > } > >+static inline JSValue jsTestGlobalObjectTestEnabledForContextConstructorGetter(ExecState& state, JSTestGlobalObject& thisObject, ThrowScope& throwScope) >+{ >+ UNUSED_PARAM(throwScope); >+ UNUSED_PARAM(state); >+ return JSTestEnabledForContext::getConstructor(state.vm(), thisObject.globalObject()); >+} >+ >+EncodedJSValue jsTestGlobalObjectTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName) >+{ >+ return IDLAttribute<JSTestGlobalObject>::get<jsTestGlobalObjectTestEnabledForContextConstructorGetter>(*state, thisValue, "TestEnabledForContext"); >+} >+ >+static inline bool setJSTestGlobalObjectTestEnabledForContextConstructorSetter(ExecState& state, JSTestGlobalObject& thisObject, JSValue value, ThrowScope& throwScope) >+{ >+ UNUSED_PARAM(throwScope); >+ // Shadowing a built-in constructor. >+ return thisObject.putDirect(state.vm(), Identifier::fromString(&state.vm(), reinterpret_cast<const LChar*>("TestEnabledForContext"), strlen("TestEnabledForContext")), value); >+} >+ >+bool setJSTestGlobalObjectTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue) >+{ >+ return IDLAttribute<JSTestGlobalObject>::set<setJSTestGlobalObjectTestEnabledForContextConstructorSetter>(*state, thisValue, encodedValue, "TestEnabledForContext"); >+} >+ > static inline JSValue jsTestGlobalObjectTestEventConstructorConstructorGetter(ExecState& state, JSTestGlobalObject& thisObject, ThrowScope& throwScope) > { > UNUSED_PARAM(throwScope); >diff --git a/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl b/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl >new file mode 100644 >index 0000000000000000000000000000000000000000..2e7094453ed57222b3441ba6e98a490be97d1b92 >--- /dev/null >+++ b/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl >@@ -0,0 +1,31 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+[ >+ EnabledForContext, >+ SecureContext, >+] interface TestEnabledForContext { >+ [EnabledBySetting=TestSetting, EnabledForContext] attribute TestSubObjConstructor TestSubObjEnabledForContext; >+}; >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 0e842f1b6fce5a6c7e9e9b00aba4cc6e633cf22c..5ef2eff2f96ee5b72e1ce8e0f23776ce91c94451 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,20 @@ >+2019-05-09 Andy Estes <aestes@apple.com> >+ >+ [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts >+ https://bugs.webkit.org/show_bug.cgi?id=197751 >+ <rdar://problem/50631563> >+ >+ Reviewed by Alex Christensen. >+ >+ Added new API tests. >+ >+ * TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm: >+ (-[TestApplePayScriptMessageHandler initWithAPIsAvailableExpectation:canMakePaymentsExpectation:]): >+ (-[TestApplePayScriptMessageHandler userContentController:didReceiveScriptMessage:]): >+ (TestWebKitAPI::TEST): >+ (-[TestApplePayScriptMessageHandler initWithExpectation:]): Deleted. >+ * TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html: >+ > 2019-05-09 Eric Carlson <eric.carlson@apple.com> > > Refine AudioSession route sharing policy >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm >index a2b5801f939bd70612c3b89fd0dbc55c8d57146f..061b331a15676b3379f36961854703eee6913a0c 100644 >--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm >@@ -41,29 +41,33 @@ static bool isDone; > @interface TestApplePayScriptMessageHandler : NSObject <WKScriptMessageHandler> > > - (instancetype)init NS_UNAVAILABLE; >-- (instancetype)initWithExpectation:(BOOL)expectation; >+- (instancetype)initWithAPIsAvailableExpectation:(BOOL)apisAvailableExpectation canMakePaymentsExpectation:(BOOL)canMakePaymentsExpectation; >+ >+@property (nonatomic, setter=setAPIsAvailableExpectation:) BOOL apisAvailableExpectation; >+@property (nonatomic) BOOL canMakePaymentsExpectation; > > @end > >-@implementation TestApplePayScriptMessageHandler { >- BOOL _expectation; >-} >+@implementation TestApplePayScriptMessageHandler > >-- (instancetype)initWithExpectation:(BOOL)expectation >+- (instancetype)initWithAPIsAvailableExpectation:(BOOL)apisAvailableExpectation canMakePaymentsExpectation:(BOOL)canMakePaymentsExpectation > { > if (!(self = [super init])) > return nil; > >- _expectation = expectation; >+ _apisAvailableExpectation = apisAvailableExpectation; >+ _canMakePaymentsExpectation = canMakePaymentsExpectation; > return self; > } > > - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message > { >- EXPECT_EQ(_expectation, [[message.body objectForKey:@"supportsVersion"] boolValue]); >- EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePayments"] boolValue]); >- EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePaymentsWithActiveCard"] boolValue]); >- EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePayment"] boolValue]); >+ EXPECT_EQ(_apisAvailableExpectation, [[message.body objectForKey:@"applePaySessionAvailable"] boolValue]); >+ EXPECT_EQ(_apisAvailableExpectation, [[message.body objectForKey:@"paymentRequestAvailable"] boolValue]); >+ EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"supportsVersion"] boolValue]); >+ EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePayments"] boolValue]); >+ EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePaymentsWithActiveCard"] boolValue]); >+ EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePayment"] boolValue]); > isDone = true; > } > >@@ -75,7 +79,7 @@ TEST(ApplePay, ApplePayAvailableByDefault) > { > [TestProtocol registerWithScheme:@"https"]; > >- auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:YES]); >+ auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]); > > WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]; > [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"]; >@@ -88,11 +92,11 @@ TEST(ApplePay, ApplePayAvailableByDefault) > [TestProtocol unregister]; > } > >-TEST(ApplePay, UserScriptDisablesApplePay) >+TEST(ApplePay, UserScriptAtDocumentStartDisablesApplePay) > { > [TestProtocol registerWithScheme:@"https"]; > >- auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:NO]); >+ auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]); > auto userScript = adoptNS([[WKUserScript alloc] initWithSource:@"window.wkUserScriptInjected = true" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]); > > WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]; >@@ -109,11 +113,32 @@ TEST(ApplePay, UserScriptDisablesApplePay) > [TestProtocol unregister]; > } > >+TEST(ApplePay, UserScriptAtDocumentEndDisablesApplePay) >+{ >+ [TestProtocol registerWithScheme:@"https"]; >+ >+ auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]); >+ auto userScript = adoptNS([[WKUserScript alloc] initWithSource:@"window.wkUserScriptInjected = true" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]); >+ >+ WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]; >+ [configuration.userContentController addUserScript:userScript.get()]; >+ [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); >+ [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]]; >+ >+ Util::run(&isDone); >+ >+ EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]); >+ >+ [TestProtocol unregister]; >+} >+ > TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePay) > { > [TestProtocol registerWithScheme:@"https"]; > >- auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:NO]); >+ auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:NO]); > > WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]; > [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"]; >@@ -130,6 +155,29 @@ TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePay) > [TestProtocol unregister]; > } > >+TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePayInExistingObjects) >+{ >+ [TestProtocol registerWithScheme:@"https"]; >+ >+ auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]); >+ >+ WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]; >+ [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); >+ [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]]; >+ >+ Util::run(&isDone); >+ >+ isDone = false; >+ [messageHandler setCanMakePaymentsExpectation:NO]; >+ [webView evaluateJavaScript:@"document.location.hash = '#test'" completionHandler:nil]; >+ >+ Util::run(&isDone); >+ >+ [TestProtocol unregister]; >+} >+ > TEST(ApplePay, ActiveSessionBlocksUserAgentScripts) > { > [TestProtocol registerWithScheme:@"https"]; >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html >index f302c6ad9f96938ad644fc07e11e3fb25ffea33a..6a8bc5a45eb238c1eae838178fe21cb5450c4daa 100644 >--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html >@@ -26,27 +26,41 @@ > }; > }; > >- window.addEventListener('load', async () => { >+ const eventListener = async () => { > internals.mockPaymentCoordinator.supportsUnrestrictedApplePay = false; > >+ const applePaySessionAvailable = !!window.ApplePaySession; >+ const paymentRequestAvailable = !!window.PaymentRequest; >+ if (!applePaySessionAvailable || !paymentRequestAvailable) { >+ window.webkit.messageHandlers.testApplePay.postMessage({ applePaySessionAvailable, paymentRequestAvailable }); >+ return; >+ } >+ > const supportsVersion = ApplePaySession.supportsVersion(1); > const canMakePayments = ApplePaySession.canMakePayments(); > const canMakePaymentsWithActiveCard = await ApplePaySession.canMakePaymentsWithActiveCard(''); > >- const paymentRequest = new PaymentRequest([applePayMethod()], { >- total: { >- label: 'total', >- amount: { currency: 'USD', value: '0.00' }, >- }, >- }); >+ if (!window.wkPaymentRequest) { >+ wkPaymentRequest = new PaymentRequest([applePayMethod()], { >+ total: { >+ label: 'total', >+ amount: { currency: 'USD', value: '0.00' }, >+ }, >+ }); >+ } > >- const canMakePayment = await paymentRequest.canMakePayment(); >+ const canMakePayment = await wkPaymentRequest.canMakePayment(); > > window.webkit.messageHandlers.testApplePay.postMessage({ >+ applePaySessionAvailable, >+ paymentRequestAvailable, > supportsVersion, > canMakePayments, > canMakePaymentsWithActiveCard, > canMakePayment, > }); >- }); >+ }; >+ >+ window.addEventListener('load', eventListener); >+ window.addEventListener('hashchange', eventListener); > </script>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197751
:
369514
|
369516
|
369616
|
369620
| 369889