Diff
Modified: trunk/Source/WebCore/ChangeLog (245313 => 245314)
--- trunk/Source/WebCore/ChangeLog 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/ChangeLog 2019-05-14 22:50:21 UTC (rev 245314)
@@ -1,3 +1,57 @@
+2019-05-14 Andy Estes <[email protected]>
+
+ [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-14 Robin Morisset <[email protected]>
[WHLSL] parseEffectfulSuffix() is never called
Modified: trunk/Source/WebCore/Modules/applepay/ApplePaySession.idl (245313 => 245314)
--- trunk/Source/WebCore/Modules/applepay/ApplePaySession.idl 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/applepay/ApplePaySession.idl 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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;
Modified: trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp (245313 => 245314)
--- trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 @@
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()) {
Modified: trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.h (245313 => 245314)
--- trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.h 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.h 2019-05-14 22:50:21 UTC (rev 245314)
@@ -78,6 +78,7 @@
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;
Modified: trunk/Source/WebCore/Modules/applepay/PaymentSession.cpp (245313 => 245314)
--- trunk/Source/WebCore/Modules/applepay/PaymentSession.cpp 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/applepay/PaymentSession.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 @@
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)
Modified: trunk/Source/WebCore/Modules/applepay/PaymentSession.h (245313 => 245314)
--- trunk/Source/WebCore/Modules/applepay/PaymentSession.h 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/applepay/PaymentSession.h 2019-05-14 22:50:21 UTC (rev 245314)
@@ -41,6 +41,7 @@
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;
Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp (245313 => 245314)
--- trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 @@
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)
Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h (245313 => 245314)
--- trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h 2019-05-14 22:50:21 UTC (rev 245314)
@@ -46,6 +46,7 @@
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;
Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp (245313 => 245314)
--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 @@
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) }
Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h (245313 => 245314)
--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h 2019-05-14 22:50:21 UTC (rev 245314)
@@ -58,6 +58,7 @@
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&&);
Modified: trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl (245313 => 245314)
--- trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl 2019-05-14 22:50:21 UTC (rev 245314)
@@ -30,6 +30,7 @@
ConstructorCallWith=Document,
ConstructorMayThrowException,
EnabledBySetting=PaymentRequest,
+ EnabledForContext,
SecureContext,
] interface PaymentRequest : EventTarget {
[CallWith=Document] Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (245313 => 245314)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2019-05-14 22:50:21 UTC (rev 245314)
@@ -1705,6 +1705,7 @@
}
return $context->extendedAttributes->{EnabledAtRuntime}
+ || $context->extendedAttributes->{EnabledForContext}
|| $context->extendedAttributes->{EnabledForWorld}
|| $context->extendedAttributes->{EnabledBySetting}
|| $context->extendedAttributes->{DisabledByQuirk}
@@ -3788,6 +3789,15 @@
}
}
+ 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;
Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.json (245313 => 245314)
--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.json 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.json 2019-05-14 22:50:21 UTC (rev 245314)
@@ -192,6 +192,9 @@
"contextsAllowed": ["interface", "dictionary", "enum", "attribute", "operation", "constant"],
"values": ["*"]
},
+ "EnabledForContext": {
+ "contextsAllowed": ["attribute", "interface"]
+ },
"EnabledForWorld": {
"contextsAllowed": ["attribute", "operation"],
"values": ["*"]
Modified: trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl (245313 => 245314)
--- trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl 2019-05-14 22:50:21 UTC (rev 245314)
@@ -283,7 +283,7 @@
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);
Added: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp (0 => 245314)
--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp (rev 0)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 <_javascript_Core/FunctionPrototype.h>
+#include <_javascript_Core/HeapSnapshotBuilder.h>
+#include <_javascript_Core/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;
+}
+
+}
Added: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h (0 => 245314)
--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h (rev 0)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledForContext.h 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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
Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp (245313 => 245314)
--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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 @@
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 @@
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 @@
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);
Copied: trunk/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl (from rev 245313, trunk/Source/WebCore/Modules/applepay/PaymentSession.h) (0 => 245314)
--- trunk/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl (rev 0)
+++ trunk/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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;
+};
Modified: trunk/Tools/ChangeLog (245313 => 245314)
--- trunk/Tools/ChangeLog 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Tools/ChangeLog 2019-05-14 22:50:21 UTC (rev 245314)
@@ -1,3 +1,20 @@
+2019-05-14 Andy Estes <[email protected]>
+
+ [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-14 Youenn Fablet <[email protected]>
A service worker process should app nap when all its clients app nap
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm (245313 => 245314)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm 2019-05-14 22:50:21 UTC (rev 245314)
@@ -41,29 +41,33 @@
@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 @@
{
[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 @@
[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 @@
[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 @@
[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"];
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html (245313 => 245314)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html 2019-05-14 22:44:26 UTC (rev 245313)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html 2019-05-14 22:50:21 UTC (rev 245314)
@@ -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>