Changeset 245314 in webkit


Ignore:
Timestamp:
May 14, 2019 3:50:21 PM (5 years ago)
Author:
aestes@apple.com
Message:

[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.

Source/WebCore:

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.

Tools:

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:
Location:
trunk
Files:
2 added
18 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r245312 r245314  
     12019-05-14  Andy Estes  <aestes@apple.com>
     2
     3        [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts
     4        https://bugs.webkit.org/show_bug.cgi?id=197751
     5        <rdar://problem/50631563>
     6
     7        Reviewed by Alex Christensen.
     8
     9        In r243324, when a document has had user agent scripts injected into it, payment APIs were
     10        disabled at runtime by having all entry points return falsy values or throw exceptions
     11        (e.g., ApplePaySession.canMakePayments() returns false).
     12
     13        In the case of user scripts in particular (e.g., WKUserScript), since we know whether these
     14        exist at the time we create a document's DOMWindow, we can do better than r243324 by
     15        completely disabling the payment APIs in the presence of user scripts.
     16
     17        To achieve this, this change introduces the 'EnabledByContext' extended attribute for
     18        interfaces, which instructs the bindings generator to add a conjunct to the payment API
     19        constructors that asks the interface's implementation class whether it should be enabled for
     20        a given ScriptExecutionContext. The PaymentRequest and ApplePaySession interfaces adopt this
     21        new extended attribute to implement the new user script check.
     22
     23        Added new API tests.
     24
     25        * Modules/applepay/ApplePaySession.idl:
     26        * Modules/applepay/PaymentCoordinator.cpp:
     27        (WebCore::PaymentCoordinator::shouldEnableApplePayAPIs const):
     28        * Modules/applepay/PaymentCoordinator.h:
     29        * Modules/applepay/PaymentSession.cpp:
     30        (WebCore::PaymentSession::enabledForContext):
     31        * Modules/applepay/PaymentSession.h:
     32        * Modules/paymentrequest/PaymentHandler.cpp:
     33        (WebCore::PaymentHandler::enabledForContext):
     34        * Modules/paymentrequest/PaymentHandler.h:
     35        * Modules/paymentrequest/PaymentRequest.cpp:
     36        (WebCore::PaymentRequest::enabledForContext):
     37        * Modules/paymentrequest/PaymentRequest.h:
     38        * Modules/paymentrequest/PaymentRequest.idl:
     39        * bindings/scripts/CodeGeneratorJS.pm:
     40        (NeedsRuntimeCheck):
     41        (GenerateRuntimeEnableConditionalString):
     42        * bindings/scripts/IDLAttributes.json:
     43        * bindings/scripts/preprocess-idls.pl:
     44        (GenerateConstructorAttributes):
     45        * bindings/scripts/test/JS/JSTestEnabledForContext.cpp: Added.
     46        * bindings/scripts/test/JS/JSTestEnabledForContext.h: Added.
     47        * bindings/scripts/test/JS/JSTestGlobalObject.cpp:
     48        (WebCore::JSTestGlobalObject::finishCreation):
     49        (WebCore::jsTestGlobalObjectTestEnabledForContextConstructorGetter):
     50        (WebCore::jsTestGlobalObjectTestEnabledForContextConstructor):
     51        (WebCore::setJSTestGlobalObjectTestEnabledForContextConstructorSetter):
     52        (WebCore::setJSTestGlobalObjectTestEnabledForContextConstructor):
     53        * bindings/scripts/test/TestEnabledForContext.idl: Added.
     54
    1552019-05-14  Robin Morisset  <rmorisset@apple.com>
    256
  • trunk/Source/WebCore/Modules/applepay/ApplePaySession.idl

    r243324 r245314  
    3131    ConstructorMayThrowException,
    3232    EnabledBySetting=ApplePay,
     33    EnabledForContext,
    3334] interface ApplePaySession : EventTarget {
    3435    const unsigned short STATUS_SUCCESS = 0;
  • trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.cpp

    r244092 r245314  
    3232#include "LinkIconCollector.h"
    3333#include "Logging.h"
     34#include "Page.h"
    3435#include "PaymentAuthorizationStatus.h"
    3536#include "PaymentCoordinatorClient.h"
    3637#include "PaymentSession.h"
     38#include "UserContentProvider.h"
    3739#include <wtf/CompletionHandler.h>
    3840#include <wtf/URL.h>
     
    250252
    251253    return m_client.validatedPaymentNetwork(paymentNetwork);
     254}
     255
     256bool PaymentCoordinator::shouldEnableApplePayAPIs(Document& document) const
     257{
     258    if (m_client.supportsUnrestrictedApplePay()) {
     259        RELEASE_LOG_IF_ALLOWED("shouldEnableApplePayAPIs() -> true (unrestricted client)");
     260        return true;
     261    }
     262
     263    bool shouldEnableAPIs = true;
     264    document.page()->userContentProvider().forEachUserScript([&](DOMWrapperWorld&, const UserScript&) {
     265        shouldEnableAPIs = false;
     266    });
     267
     268    RELEASE_LOG_IF_ALLOWED("shouldEnableApplePayAPIs() -> %d", shouldEnableAPIs);
     269    return shouldEnableAPIs;
    252270}
    253271
  • trunk/Source/WebCore/Modules/applepay/PaymentCoordinator.h

    r243324 r245314  
    7979    Optional<String> validatedPaymentNetwork(Document&, unsigned version, const String&) const;
    8080
     81    bool shouldEnableApplePayAPIs(Document&) const;
    8182    WEBCORE_EXPORT bool shouldAllowApplePay(Document&) const;
    8283    WEBCORE_EXPORT bool shouldAllowUserAgentScripts(Document&) const;
  • trunk/Source/WebCore/Modules/applepay/PaymentSession.cpp

    r224061 r245314  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3131#include "Document.h"
    3232#include "DocumentLoader.h"
     33#include "Page.h"
    3334#include "SecurityOrigin.h"
    3435
     
    7374}
    7475
     76bool PaymentSession::enabledForContext(ScriptExecutionContext& context)
     77{
     78    auto& document = downcast<Document>(context);
     79    if (auto page = document.page())
     80        return page->paymentCoordinator().shouldEnableApplePayAPIs(document);
     81
     82    return false;
     83}
     84
    7585} // namespace WebCore
    7686
  • trunk/Source/WebCore/Modules/applepay/PaymentSession.h

    r238771 r245314  
    4242public:
    4343    static ExceptionOr<void> canCreateSession(Document&);
     44    static bool enabledForContext(ScriptExecutionContext&);
    4445
    4546    virtual unsigned version() const = 0;
  • trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp

    r224061 r245314  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6262}
    6363
     64bool PaymentHandler::enabledForContext(ScriptExecutionContext& context)
     65{
     66#if ENABLE(APPLE_PAY)
     67    return PaymentSession::enabledForContext(context);
     68#else
     69    UNUSED_PARAM(context);
     70    return false;
     71#endif
     72}
     73
    6474bool PaymentHandler::hasActiveSession(Document& document)
    6575{
  • trunk/Source/WebCore/Modules/paymentrequest/PaymentHandler.h

    r243324 r245314  
    4747    static RefPtr<PaymentHandler> create(Document&, PaymentRequest&, const PaymentRequest::MethodIdentifier&);
    4848    static ExceptionOr<void> canCreateSession(Document&);
     49    static bool enabledForContext(ScriptExecutionContext&);
    4950    static bool hasActiveSession(Document&);
    5051
  • trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp

    r243887 r245314  
    3535#include "JSPaymentDetailsUpdate.h"
    3636#include "JSPaymentResponse.h"
     37#include "Page.h"
    3738#include "PaymentAddress.h"
     39#include "PaymentCoordinator.h"
    3840#include "PaymentCurrencyAmount.h"
    3941#include "PaymentDetailsInit.h"
     
    352354}
    353355
     356bool PaymentRequest::enabledForContext(ScriptExecutionContext& context)
     357{
     358    return PaymentHandler::enabledForContext(context);
     359}
     360
    354361PaymentRequest::PaymentRequest(Document& document, PaymentOptions&& options, PaymentDetailsInit&& details, Vector<String>&& serializedModifierData, Vector<Method>&& serializedMethodData, String&& selectedShippingOption)
    355362    : ActiveDOMObject { document }
  • trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.h

    r243887 r245314  
    5959
    6060    static ExceptionOr<Ref<PaymentRequest>> create(Document&, Vector<PaymentMethodData>&&, PaymentDetailsInit&&, PaymentOptions&&);
     61    static bool enabledForContext(ScriptExecutionContext&);
    6162    ~PaymentRequest();
    6263
  • trunk/Source/WebCore/Modules/paymentrequest/PaymentRequest.idl

    r237597 r245314  
    3131    ConstructorMayThrowException,
    3232    EnabledBySetting=PaymentRequest,
     33    EnabledForContext,
    3334    SecureContext,
    3435] interface PaymentRequest : EventTarget {
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r245082 r245314  
    17061706
    17071707    return $context->extendedAttributes->{EnabledAtRuntime}
     1708        || $context->extendedAttributes->{EnabledForContext}
    17081709        || $context->extendedAttributes->{EnabledForWorld}
    17091710        || $context->extendedAttributes->{EnabledBySetting}
     
    37873788            }
    37883789        }
     3790    }
     3791
     3792    if ($context->extendedAttributes->{EnabledForContext}) {
     3793        assert("Must not specify value for EnabledForContext.") unless $context->extendedAttributes->{EnabledForContext} eq "VALUE_IS_MISSING";
     3794        assert("EnabledForContext must be an interface or constructor attribute.") unless $codeGenerator->IsConstructorType($context->type);
     3795
     3796        my $contextRef = "*jsCast<JSDOMGlobalObject*>(" . $globalObjectPtr . ")->scriptExecutionContext()";
     3797        my $name = $context->name;
     3798        push(@conjuncts,  "${name}::enabledForContext(" . $contextRef . ")");
    37893799    }
    37903800
  • trunk/Source/WebCore/bindings/scripts/IDLAttributes.json

    r243046 r245314  
    193193            "values": ["*"]
    194194        },
     195        "EnabledForContext": {
     196            "contextsAllowed": ["attribute", "interface"]
     197        },
    195198        "EnabledForWorld": {
    196199            "contextsAllowed": ["attribute", "operation"],
  • trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl

    r245036 r245314  
    284284      next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledForWorld"
    285285        || $attributeName eq "EnabledBySetting" || $attributeName eq "SecureContext" || $attributeName eq "PrivateIdentifier"
    286         || $attributeName eq "PublicIdentifier" || $attributeName eq "DisabledByQuirk" || $attributeName eq "EnabledByQuirk");
     286        || $attributeName eq "PublicIdentifier" || $attributeName eq "DisabledByQuirk" || $attributeName eq "EnabledByQuirk" || $attributeName eq "EnabledForContext");
    287287      my $extendedAttribute = $attributeName;
    288288      $extendedAttribute .= "=" . $extendedAttributes->{$attributeName} unless $extendedAttributes->{$attributeName} eq "VALUE_IS_MISSING";
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp

    r245036 r245314  
    4040#include "JSTestDomainSecurity.h"
    4141#include "JSTestEnabledBySetting.h"
     42#include "JSTestEnabledForContext.h"
    4243#include "JSTestEventConstructor.h"
    4344#include "JSTestEventTarget.h"
     
    173174JSC::EncodedJSValue jsTestGlobalObjectTestEnabledBySettingConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
    174175bool setJSTestGlobalObjectTestEnabledBySettingConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     176JSC::EncodedJSValue jsTestGlobalObjectTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     177bool setJSTestGlobalObjectTestEnabledForContextConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
    175178JSC::EncodedJSValue jsTestGlobalObjectTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
    176179bool setJSTestGlobalObjectTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     
    703706        putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().enabledAtRuntimeAttributePublicName(), CustomGetterSetter::create(vm, jsTestGlobalObjectEnabledAtRuntimeAttribute, setJSTestGlobalObjectEnabledAtRuntimeAttribute), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor)));
    704707#endif
     708    if ((jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext()->isSecureContext() && TestEnabledForContext::enabledForContext(*jsCast<JSDOMGlobalObject*>(globalObject())->scriptExecutionContext())))
     709        putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().TestEnabledForContextPublicName(), CustomGetterSetter::create(vm, jsTestGlobalObjectTestEnabledForContextConstructor, setJSTestGlobalObjectTestEnabledForContextConstructor), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum)));
    705710    putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().publicAndPrivateAttributePrivateName(), CustomGetterSetter::create(vm, jsTestGlobalObjectPublicAndPrivateAttribute, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly));
    706711#if ENABLE(TEST_FEATURE)
     
    11171122}
    11181123
     1124static inline JSValue jsTestGlobalObjectTestEnabledForContextConstructorGetter(ExecState& state, JSTestGlobalObject& thisObject, ThrowScope& throwScope)
     1125{
     1126    UNUSED_PARAM(throwScope);
     1127    UNUSED_PARAM(state);
     1128    return JSTestEnabledForContext::getConstructor(state.vm(), thisObject.globalObject());
     1129}
     1130
     1131EncodedJSValue jsTestGlobalObjectTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
     1132{
     1133    return IDLAttribute<JSTestGlobalObject>::get<jsTestGlobalObjectTestEnabledForContextConstructorGetter>(*state, thisValue, "TestEnabledForContext");
     1134}
     1135
     1136static inline bool setJSTestGlobalObjectTestEnabledForContextConstructorSetter(ExecState& state, JSTestGlobalObject& thisObject, JSValue value, ThrowScope& throwScope)
     1137{
     1138    UNUSED_PARAM(throwScope);
     1139    // Shadowing a built-in constructor.
     1140    return thisObject.putDirect(state.vm(), Identifier::fromString(&state.vm(), reinterpret_cast<const LChar*>("TestEnabledForContext"), strlen("TestEnabledForContext")), value);
     1141}
     1142
     1143bool setJSTestGlobalObjectTestEnabledForContextConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
     1144{
     1145    return IDLAttribute<JSTestGlobalObject>::set<setJSTestGlobalObjectTestEnabledForContextConstructorSetter>(*state, thisValue, encodedValue, "TestEnabledForContext");
     1146}
     1147
    11191148static inline JSValue jsTestGlobalObjectTestEventConstructorConstructorGetter(ExecState& state, JSTestGlobalObject& thisObject, ThrowScope& throwScope)
    11201149{
  • trunk/Source/WebCore/bindings/scripts/test/TestEnabledForContext.idl

    r245313 r245314  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #pragma once
    27 
    28 #if ENABLE(APPLE_PAY)
    29 
    30 #include "ApplePaySessionPaymentRequest.h"
    31 #include "ExceptionOr.h"
    32 #include "PaymentSessionBase.h"
    33 
    34 namespace WebCore {
    35 
    36 class Document;
    37 class Payment;
    38 class PaymentContact;
    39 class PaymentMethod;
    40 
    41 class PaymentSession : public virtual PaymentSessionBase {
    42 public:
    43     static ExceptionOr<void> canCreateSession(Document&);
    44 
    45     virtual unsigned version() const = 0;
    46     virtual void validateMerchant(URL&&) = 0;
    47     virtual void didAuthorizePayment(const Payment&) = 0;
    48     virtual void didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod&) = 0;
    49     virtual void didSelectShippingContact(const PaymentContact&) = 0;
    50     virtual void didSelectPaymentMethod(const PaymentMethod&) = 0;
    51     virtual void didCancelPaymentSession() = 0;
     26[
     27    EnabledForContext,
     28    SecureContext,
     29] interface TestEnabledForContext {
     30    [EnabledBySetting=TestSetting, EnabledForContext] attribute TestSubObjConstructor TestSubObjEnabledForContext;
    5231};
    53 
    54 } // namespace WebCore
    55 
    56 #endif // ENABLE(APPLE_PAY)
  • trunk/Tools/ChangeLog

    r245299 r245314  
     12019-05-14  Andy Estes  <aestes@apple.com>
     2
     3        [Apple Pay] Payment APIs should be completely disabled in web views into which clients have injected user scripts
     4        https://bugs.webkit.org/show_bug.cgi?id=197751
     5        <rdar://problem/50631563>
     6
     7        Reviewed by Alex Christensen.
     8
     9        Added new API tests.
     10
     11        * TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm:
     12        (-[TestApplePayScriptMessageHandler initWithAPIsAvailableExpectation:canMakePaymentsExpectation:]):
     13        (-[TestApplePayScriptMessageHandler userContentController:didReceiveScriptMessage:]):
     14        (TestWebKitAPI::TEST):
     15        (-[TestApplePayScriptMessageHandler initWithExpectation:]): Deleted.
     16        * TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html:
     17
    1182019-05-14  Youenn Fablet  <youenn@apple.com>
    219
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm

    r243324 r245314  
    4242
    4343- (instancetype)init NS_UNAVAILABLE;
    44 - (instancetype)initWithExpectation:(BOOL)expectation;
     44- (instancetype)initWithAPIsAvailableExpectation:(BOOL)apisAvailableExpectation canMakePaymentsExpectation:(BOOL)canMakePaymentsExpectation;
     45
     46@property (nonatomic, setter=setAPIsAvailableExpectation:) BOOL apisAvailableExpectation;
     47@property (nonatomic) BOOL canMakePaymentsExpectation;
    4548
    4649@end
    4750
    48 @implementation TestApplePayScriptMessageHandler {
    49     BOOL _expectation;
    50 }
    51 
    52 - (instancetype)initWithExpectation:(BOOL)expectation
     51@implementation TestApplePayScriptMessageHandler
     52
     53- (instancetype)initWithAPIsAvailableExpectation:(BOOL)apisAvailableExpectation canMakePaymentsExpectation:(BOOL)canMakePaymentsExpectation
    5354{
    5455    if (!(self = [super init]))
    5556        return nil;
    5657
    57     _expectation = expectation;
     58    _apisAvailableExpectation = apisAvailableExpectation;
     59    _canMakePaymentsExpectation = canMakePaymentsExpectation;
    5860    return self;
    5961}
     
    6163- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
    6264{
    63     EXPECT_EQ(_expectation, [[message.body objectForKey:@"supportsVersion"] boolValue]);
    64     EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePayments"] boolValue]);
    65     EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePaymentsWithActiveCard"] boolValue]);
    66     EXPECT_EQ(_expectation, [[message.body objectForKey:@"canMakePayment"] boolValue]);
     65    EXPECT_EQ(_apisAvailableExpectation, [[message.body objectForKey:@"applePaySessionAvailable"] boolValue]);
     66    EXPECT_EQ(_apisAvailableExpectation, [[message.body objectForKey:@"paymentRequestAvailable"] boolValue]);
     67    EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"supportsVersion"] boolValue]);
     68    EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePayments"] boolValue]);
     69    EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePaymentsWithActiveCard"] boolValue]);
     70    EXPECT_EQ(_canMakePaymentsExpectation, [[message.body objectForKey:@"canMakePayment"] boolValue]);
    6771    isDone = true;
    6872}
     
    7680    [TestProtocol registerWithScheme:@"https"];
    7781
    78     auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:YES]);
    79 
    80     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
    81     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
    82 
    83     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
    84     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]];
    85 
    86     Util::run(&isDone);
    87 
    88     [TestProtocol unregister];
    89 }
    90 
    91 TEST(ApplePay, UserScriptDisablesApplePay)
    92 {
    93     [TestProtocol registerWithScheme:@"https"];
    94 
    95     auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:NO]);
     82    auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]);
     83
     84    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
     85    [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
     86
     87    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
     88    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]];
     89
     90    Util::run(&isDone);
     91
     92    [TestProtocol unregister];
     93}
     94
     95TEST(ApplePay, UserScriptAtDocumentStartDisablesApplePay)
     96{
     97    [TestProtocol registerWithScheme:@"https"];
     98
     99    auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]);
    96100    auto userScript = adoptNS([[WKUserScript alloc] initWithSource:@"window.wkUserScriptInjected = true" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
    97101
     
    110114}
    111115
     116TEST(ApplePay, UserScriptAtDocumentEndDisablesApplePay)
     117{
     118    [TestProtocol registerWithScheme:@"https"];
     119   
     120    auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]);
     121    auto userScript = adoptNS([[WKUserScript alloc] initWithSource:@"window.wkUserScriptInjected = true" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]);
     122   
     123    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
     124    [configuration.userContentController addUserScript:userScript.get()];
     125    [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
     126   
     127    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
     128    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]];
     129   
     130    Util::run(&isDone);
     131   
     132    EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkUserScriptInjected"] boolValue]);
     133   
     134    [TestProtocol unregister];
     135}
     136
    112137TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePay)
    113138{
    114139    [TestProtocol registerWithScheme:@"https"];
    115140
    116     auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithExpectation:NO]);
     141    auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:NO]);
    117142
    118143    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
     
    127152
    128153    EXPECT_EQ(YES, [[webView objectByEvaluatingJavaScript:@"window.wkScriptEvaluated"] boolValue]);
     154
     155    [TestProtocol unregister];
     156}
     157
     158TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePayInExistingObjects)
     159{
     160    [TestProtocol registerWithScheme:@"https"];
     161
     162    auto messageHandler = adoptNS([[TestApplePayScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]);
     163
     164    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
     165    [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
     166
     167    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
     168    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://bundle-html-file/apple-pay-availability"]]];
     169
     170    Util::run(&isDone);
     171
     172    isDone = false;
     173    [messageHandler setCanMakePaymentsExpectation:NO];
     174    [webView evaluateJavaScript:@"document.location.hash = '#test'" completionHandler:nil];
     175
     176    Util::run(&isDone);
    129177
    130178    [TestProtocol unregister];
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-pay-availability.html

    r243324 r245314  
    2727    };
    2828
    29     window.addEventListener('load', async () => {
     29    const eventListener = async () => {
    3030        internals.mockPaymentCoordinator.supportsUnrestrictedApplePay = false;
     31
     32        const applePaySessionAvailable = !!window.ApplePaySession;
     33        const paymentRequestAvailable = !!window.PaymentRequest;
     34        if (!applePaySessionAvailable || !paymentRequestAvailable) {
     35            window.webkit.messageHandlers.testApplePay.postMessage({ applePaySessionAvailable, paymentRequestAvailable });
     36            return;
     37        }
    3138
    3239        const supportsVersion = ApplePaySession.supportsVersion(1);
     
    3441        const canMakePaymentsWithActiveCard = await ApplePaySession.canMakePaymentsWithActiveCard('');
    3542
    36         const paymentRequest = new PaymentRequest([applePayMethod()], {
    37             total: {
    38                 label: 'total',
    39                 amount: { currency: 'USD', value: '0.00' },
    40             },
    41         });
     43        if (!window.wkPaymentRequest) {
     44            wkPaymentRequest = new PaymentRequest([applePayMethod()], {
     45                total: {
     46                    label: 'total',
     47                    amount: { currency: 'USD', value: '0.00' },
     48                },
     49            });
     50        }
    4251
    43         const canMakePayment = await paymentRequest.canMakePayment();
     52        const canMakePayment = await wkPaymentRequest.canMakePayment();
    4453
    4554        window.webkit.messageHandlers.testApplePay.postMessage({
     55            applePaySessionAvailable,
     56            paymentRequestAvailable,
    4657            supportsVersion,
    4758            canMakePayments,
     
    4960            canMakePayment,
    5061        });
    51     });
     62    };
     63
     64    window.addEventListener('load', eventListener);
     65    window.addEventListener('hashchange', eventListener);
    5266</script>
Note: See TracChangeset for help on using the changeset viewer.