/* * 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 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& 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 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& 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(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& newShippingMethods, const std::optional& 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(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& 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(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