diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/ApplePay')
3 files changed, 553 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.cpp b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.cpp new file mode 100644 index 000000000..92a19f8e3 --- /dev/null +++ b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2015, 2016 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. + */ + +#include "config.h" +#include "WebPaymentCoordinatorProxy.h" + +#if ENABLE(APPLE_PAY) + +#include "WebPageProxy.h" +#include "WebPaymentCoordinatorMessages.h" +#include "WebPaymentCoordinatorProxyMessages.h" +#include "WebProcessProxy.h" +#include <WebCore/PaymentAuthorizationStatus.h> + +namespace WebKit { + +static WebPaymentCoordinatorProxy* activePaymentCoordinatorProxy; + +WebPaymentCoordinatorProxy::WebPaymentCoordinatorProxy(WebPageProxy& webPageProxy) + : m_webPageProxy(webPageProxy) + , m_weakPtrFactory(this) + , m_state(State::Idle) + , m_merchantValidationState(MerchantValidationState::Idle) +{ + m_webPageProxy.process().addMessageReceiver(Messages::WebPaymentCoordinatorProxy::messageReceiverName(), m_webPageProxy.pageID(), *this); +} + +WebPaymentCoordinatorProxy::~WebPaymentCoordinatorProxy() +{ + if (activePaymentCoordinatorProxy == this) + activePaymentCoordinatorProxy = nullptr; + + if (m_state != State::Idle) + hidePaymentUI(); + + m_webPageProxy.process().removeMessageReceiver(Messages::WebPaymentCoordinatorProxy::messageReceiverName(), m_webPageProxy.pageID()); +} + +void WebPaymentCoordinatorProxy::canMakePayments(bool& reply) +{ + reply = platformCanMakePayments(); +} + +void WebPaymentCoordinatorProxy::canMakePaymentsWithActiveCard(const String& merchantIdentifier, const String& domainName, uint64_t requestID) +{ + auto weakThis = m_weakPtrFactory.createWeakPtr(); + platformCanMakePaymentsWithActiveCard(merchantIdentifier, domainName, [weakThis, requestID](bool canMakePayments) { + auto paymentCoordinatorProxy = weakThis.get(); + if (!paymentCoordinatorProxy) + return; + + paymentCoordinatorProxy->m_webPageProxy.send(Messages::WebPaymentCoordinator::CanMakePaymentsWithActiveCardReply(requestID, canMakePayments)); + }); +} + +void WebPaymentCoordinatorProxy::openPaymentSetup(const String& merchantIdentifier, const String& domainName, uint64_t requestID) +{ + auto weakThis = m_weakPtrFactory.createWeakPtr(); + platformOpenPaymentSetup(merchantIdentifier, domainName, [weakThis, requestID](bool result) { + auto paymentCoordinatorProxy = weakThis.get(); + if (!paymentCoordinatorProxy) + return; + + paymentCoordinatorProxy->m_webPageProxy.send(Messages::WebPaymentCoordinator::OpenPaymentSetupReply(requestID, result)); + }); +} + +void WebPaymentCoordinatorProxy::showPaymentUI(const String& originatingURLString, const Vector<String>& linkIconURLStrings, const WebCore::PaymentRequest& paymentRequest, bool& result) +{ + // FIXME: Make this a message check. + ASSERT(canBegin()); + + if (activePaymentCoordinatorProxy) { + activePaymentCoordinatorProxy->hidePaymentUI(); + activePaymentCoordinatorProxy->didCancelPayment(); + } + + activePaymentCoordinatorProxy = this; + + m_state = State::Activating; + + WebCore::URL originatingURL(WebCore::URL(), originatingURLString); + + Vector<WebCore::URL> linkIconURLs; + for (const auto& linkIconURLString : linkIconURLStrings) + linkIconURLs.append(WebCore::URL(WebCore::URL(), linkIconURLString)); + + platformShowPaymentUI(originatingURL, linkIconURLs, paymentRequest, [this](bool result) { + ASSERT(m_state == State::Activating); + if (!result) { + didCancelPayment(); + return; + } + + m_state = State::Active; + }); + + result = true; +} + +static bool isValidEnum(WebCore::PaymentAuthorizationStatus status) +{ + switch (status) { + case WebCore::PaymentAuthorizationStatus::Success: + case WebCore::PaymentAuthorizationStatus::Failure: + case WebCore::PaymentAuthorizationStatus::InvalidBillingPostalAddress: + case WebCore::PaymentAuthorizationStatus::InvalidShippingPostalAddress: + case WebCore::PaymentAuthorizationStatus::InvalidShippingContact: + case WebCore::PaymentAuthorizationStatus::PINRequired: + case WebCore::PaymentAuthorizationStatus::PINIncorrect: + case WebCore::PaymentAuthorizationStatus::PINLockout: + return true; + } + + return false; +} + +void WebPaymentCoordinatorProxy::completeMerchantValidation(const WebCore::PaymentMerchantSession& paymentMerchantSession) +{ + // It's possible that the payment has been canceled already. + if (m_state == State::Idle) + return; + + // FIXME: This should be a MESSAGE_CHECK. + ASSERT(m_merchantValidationState == MerchantValidationState::Validating); + + platformCompleteMerchantValidation(paymentMerchantSession); + m_merchantValidationState = MerchantValidationState::ValidationComplete; +} + +void WebPaymentCoordinatorProxy::completeShippingMethodSelection(uint32_t opaqueStatus, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>& newTotalAndLineItems) +{ + // It's possible that the payment has been canceled already. + if (m_state == State::Idle) + return; + + // FIXME: This should be a MESSAGE_CHECK. + ASSERT(m_state == State::ShippingMethodSelected); + + auto status = static_cast<WebCore::PaymentAuthorizationStatus>(opaqueStatus); + + // FIXME: Make this a message check. + RELEASE_ASSERT(isValidEnum(status)); + + platformCompleteShippingMethodSelection(status, newTotalAndLineItems); + m_state = State::Active; +} + +void WebPaymentCoordinatorProxy::completeShippingContactSelection(uint32_t opaqueStatus, const Vector<WebCore::PaymentRequest::ShippingMethod>& newShippingMethods, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>& newTotalAndLineItems) +{ + // It's possible that the payment has been canceled already. + if (m_state == State::Idle) + return; + + // FIXME: This should be a MESSAGE_CHECK. + ASSERT(m_state == State::ShippingContactSelected); + + auto status = static_cast<WebCore::PaymentAuthorizationStatus>(opaqueStatus); + + // FIXME: Make this a message check. + RELEASE_ASSERT(isValidEnum(status)); + + platformCompleteShippingContactSelection(status, newShippingMethods, newTotalAndLineItems); + m_state = State::Active; +} + +void WebPaymentCoordinatorProxy::completePaymentMethodSelection(const std::optional<WebCore::PaymentRequest::TotalAndLineItems>& newTotalAndLineItems) +{ + // It's possible that the payment has been canceled already. + if (m_state == State::Idle) + return; + + // FIXME: This should be a MESSAGE_CHECK. + ASSERT(m_state == State::PaymentMethodSelected); + + platformCompletePaymentMethodSelection(newTotalAndLineItems); + m_state = State::Active; +} + +void WebPaymentCoordinatorProxy::completePaymentSession(uint32_t opaqueStatus) +{ + // It's possible that the payment has been canceled already. + if (!canCompletePayment()) + return; + + auto status = static_cast<WebCore::PaymentAuthorizationStatus>(opaqueStatus); + + // FIXME: Make this a message check. + RELEASE_ASSERT(isValidEnum(status)); + + platformCompletePaymentSession(status); + + if (!WebCore::isFinalStateStatus(status)) { + m_state = State::Active; + return; + } + + didReachFinalState(); +} + +void WebPaymentCoordinatorProxy::abortPaymentSession() +{ + // It's possible that the payment has been canceled already. + if (!canAbort()) + return; + + hidePaymentUI(); + + didReachFinalState(); +} + +void WebPaymentCoordinatorProxy::didCancelPayment() +{ + ASSERT(canCancel()); + + m_webPageProxy.send(Messages::WebPaymentCoordinator::DidCancelPayment()); + + didReachFinalState(); +} + +void WebPaymentCoordinatorProxy::validateMerchant(const WebCore::URL& url) +{ + ASSERT(m_merchantValidationState == MerchantValidationState::Idle); + + m_merchantValidationState = MerchantValidationState::Validating; + m_webPageProxy.send(Messages::WebPaymentCoordinator::ValidateMerchant(url.string())); +} + +void WebPaymentCoordinatorProxy::didAuthorizePayment(const WebCore::Payment& payment) +{ + m_state = State::Authorized; + m_webPageProxy.send(Messages::WebPaymentCoordinator::DidAuthorizePayment(payment)); +} + +void WebPaymentCoordinatorProxy::didSelectShippingMethod(const WebCore::PaymentRequest::ShippingMethod& shippingMethod) +{ + ASSERT(m_state == State::Active); + + m_state = State::ShippingMethodSelected; + m_webPageProxy.send(Messages::WebPaymentCoordinator::DidSelectShippingMethod(shippingMethod)); +} + +void WebPaymentCoordinatorProxy::didSelectShippingContact(const WebCore::PaymentContact& shippingContact) +{ + ASSERT(m_state == State::Active); + + m_state = State::ShippingContactSelected; + m_webPageProxy.send(Messages::WebPaymentCoordinator::DidSelectShippingContact(shippingContact)); +} + +void WebPaymentCoordinatorProxy::didSelectPaymentMethod(const WebCore::PaymentMethod& paymentMethod) +{ + ASSERT(m_state == State::Active); + + m_state = State::PaymentMethodSelected; + m_webPageProxy.send(Messages::WebPaymentCoordinator::DidSelectPaymentMethod(paymentMethod)); +} + +bool WebPaymentCoordinatorProxy::canBegin() const +{ + switch (m_state) { + case State::Idle: + return true; + + case State::Activating: + case State::Active: + case State::Authorized: + case State::ShippingMethodSelected: + case State::ShippingContactSelected: + case State::PaymentMethodSelected: + return false; + } +} + +bool WebPaymentCoordinatorProxy::canCancel() const +{ + switch (m_state) { + case State::Activating: + case State::Active: + case State::Authorized: + case State::ShippingMethodSelected: + case State::ShippingContactSelected: + case State::PaymentMethodSelected: + return true; + + case State::Idle: + return false; + } +} + +bool WebPaymentCoordinatorProxy::canCompletePayment() const +{ + switch (m_state) { + case State::Authorized: + return true; + + case State::Idle: + case State::Activating: + case State::Active: + case State::ShippingMethodSelected: + case State::ShippingContactSelected: + case State::PaymentMethodSelected: + return false; + } +} + +bool WebPaymentCoordinatorProxy::canAbort() const +{ + switch (m_state) { + case State::Activating: + case State::Active: + case State::Authorized: + case State::ShippingMethodSelected: + case State::ShippingContactSelected: + case State::PaymentMethodSelected: + return true; + + case State::Idle: + return false; + } +} + +void WebPaymentCoordinatorProxy::didReachFinalState() +{ + m_state = State::Idle; + m_merchantValidationState = MerchantValidationState::Idle; + + ASSERT(activePaymentCoordinatorProxy == this); + activePaymentCoordinatorProxy = nullptr; +} + +} + +#endif diff --git a/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.h b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.h new file mode 100644 index 000000000..c26f7ceee --- /dev/null +++ b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015 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. + */ + +#pragma once + +#if ENABLE(APPLE_PAY) + +#include "MessageReceiver.h" +#include <WebCore/PaymentHeaders.h> +#include <wtf/Forward.h> +#include <wtf/RetainPtr.h> +#include <wtf/WeakPtr.h> + +namespace IPC { +class DataReference; +} + +namespace WebCore { +enum class PaymentAuthorizationStatus; +class Payment; +class PaymentContact; +class PaymentMerchantSession; +class PaymentMethod; +class URL; +} + +OBJC_CLASS NSObject; +OBJC_CLASS NSWindow; +OBJC_CLASS PKPaymentAuthorizationViewController; +OBJC_CLASS WKPaymentAuthorizationViewControllerDelegate; + +namespace WebKit { + +class WebPageProxy; + +class WebPaymentCoordinatorProxy : private IPC::MessageReceiver { +public: + explicit WebPaymentCoordinatorProxy(WebPageProxy&); + ~WebPaymentCoordinatorProxy(); + + void didCancelPayment(); + void validateMerchant(const WebCore::URL&); + void didAuthorizePayment(const WebCore::Payment&); + void didSelectShippingMethod(const WebCore::PaymentRequest::ShippingMethod&); + void didSelectShippingContact(const WebCore::PaymentContact&); + void didSelectPaymentMethod(const WebCore::PaymentMethod&); + + void hidePaymentUI(); + +private: + // IPC::MessageReceiver. + void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override; + void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override; + + // Message handlers. + void canMakePayments(bool& reply); + void canMakePaymentsWithActiveCard(const String& merchantIdentifier, const String& domainName, uint64_t requestID); + void openPaymentSetup(const String& merchantIdentifier, const String& domainName, uint64_t requestID); + void showPaymentUI(const String& originatingURLString, const Vector<String>& linkIconURLStrings, const WebCore::PaymentRequest&, bool& result); + void completeMerchantValidation(const WebCore::PaymentMerchantSession&); + void completeShippingMethodSelection(uint32_t opaqueStatus, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void completeShippingContactSelection(uint32_t opaqueStatus, const Vector<WebCore::PaymentRequest::ShippingMethod>& newShippingMethods, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void completePaymentMethodSelection(const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void completePaymentSession(uint32_t opaqueStatus); + void abortPaymentSession(); + + bool canBegin() const; + bool canCancel() const; + bool canCompletePayment() const; + bool canAbort() const; + + void didReachFinalState(); + + bool platformCanMakePayments(); + void platformCanMakePaymentsWithActiveCard(const String& merchantIdentifier, const String& domainName, std::function<void (bool)> completionHandler); + void platformOpenPaymentSetup(const String& merchantIdentifier, const String& domainName, std::function<void (bool)> completionHandler); + void platformShowPaymentUI(const WebCore::URL& originatingURL, const Vector<WebCore::URL>& linkIconURLs, const WebCore::PaymentRequest&, std::function<void (bool)> completionHandler); + void platformCompleteMerchantValidation(const WebCore::PaymentMerchantSession&); + void platformCompleteShippingMethodSelection(WebCore::PaymentAuthorizationStatus, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void platformCompleteShippingContactSelection(WebCore::PaymentAuthorizationStatus, const Vector<WebCore::PaymentRequest::ShippingMethod>& newShippingMethods, const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void platformCompletePaymentMethodSelection(const std::optional<WebCore::PaymentRequest::TotalAndLineItems>&); + void platformCompletePaymentSession(WebCore::PaymentAuthorizationStatus); + + WebPageProxy& m_webPageProxy; + WeakPtrFactory<WebPaymentCoordinatorProxy> m_weakPtrFactory; + + enum class State { + // Idle - Nothing's happening. + Idle, + + // Activating - Waiting to show the payment UI. + Activating, + + // Active - Showing payment UI. + Active, + + // Authorized - Dispatching the authorized event and waiting for the paymentSessionCompleted message. + Authorized, + + // ShippingMethodSelected - Dispatching the shippingmethodselected event and waiting for a reply. + ShippingMethodSelected, + + // ShippingContactSelected - Dispatching the shippingcontactselected event and waiting for a reply. + ShippingContactSelected, + + // PaymentMethodSelected - Dispatching the paymentmethodselected event and waiting for a reply. + PaymentMethodSelected, + } m_state; + + enum class MerchantValidationState { + // Idle - Nothing's happening. + Idle, + + // Validating - Dispatching the validatemerchant event and waiting for a reply. + Validating, + + // ValidationComplete - A merchant session has been sent along to PassKit. + ValidationComplete + } m_merchantValidationState; + + RetainPtr<PKPaymentAuthorizationViewController> m_paymentAuthorizationViewController; + RetainPtr<WKPaymentAuthorizationViewControllerDelegate> m_paymentAuthorizationViewControllerDelegate; + +#if PLATFORM(MAC) + uint64_t m_showPaymentUIRequestSeed { 0 }; + RetainPtr<NSWindow> m_sheetWindow; + RetainPtr<NSObject *> m_sheetWindowWillCloseObserver; +#endif +}; + +} + +#endif diff --git a/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.messages.in b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.messages.in new file mode 100644 index 000000000..8649816bd --- /dev/null +++ b/Source/WebKit2/UIProcess/ApplePay/WebPaymentCoordinatorProxy.messages.in @@ -0,0 +1,42 @@ +# Copyright (C) 2015 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. +#/ + +#if ENABLE(APPLE_PAY) + +messages -> WebPaymentCoordinatorProxy { + + CanMakePayments() -> (bool result) + CanMakePaymentsWithActiveCard(String merchantIdentifier, String domainName, uint64_t requestID) + OpenPaymentSetup(String merchantIdentifier, String domainName, uint64_t requestID) + + ShowPaymentUI(String originatingURLString, Vector<String> linkIconURLStrings, WebCore::PaymentRequest paymentRequest) -> (bool result) + CompleteMerchantValidation(WebCore::PaymentMerchantSession paymentMerchantSession); + CompleteShippingMethodSelection(uint32_t opaqueStatus, std::optional<WebCore::PaymentRequest::TotalAndLineItems> newTotalAndItems) + CompleteShippingContactSelection(uint32_t opaqueStatus, Vector<WebCore::PaymentRequest::ShippingMethod> newShippingMethods, std::optional<WebCore::PaymentRequest::TotalAndLineItems> newTotalAndItems) + CompletePaymentMethodSelection(std::optional<WebCore::PaymentRequest::TotalAndLineItems> newTotalAndItems) + CompletePaymentSession(uint32_t opaqueStatus) + AbortPaymentSession() +} + +#endif |