| /* |
| * Copyright (C) 2021 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 "ApplePayAMSUIPaymentHandler.h" |
| |
| #if ENABLE(APPLE_PAY_AMS_UI) && ENABLE(PAYMENT_REQUEST) |
| |
| #include "ApplePayAMSUIRequest.h" |
| #include "Document.h" |
| #include "JSApplePayAMSUIRequest.h" |
| #include "JSDOMConvert.h" |
| #include "Page.h" |
| |
| namespace WebCore { |
| |
| static ExceptionOr<ApplePayAMSUIRequest> convertAndValidateApplePayAMSUIRequest(Document& document, JSC::JSValue data) |
| { |
| if (data.isEmpty()) |
| return Exception { TypeError, "Missing payment method data."_s }; |
| |
| auto throwScope = DECLARE_THROW_SCOPE(document.vm()); |
| auto applePayAMSUIRequest = convertDictionary<ApplePayAMSUIRequest>(*document.globalObject(), data); |
| if (throwScope.exception()) |
| return Exception { ExistingExceptionError }; |
| |
| if (!applePayAMSUIRequest.engagementRequest.startsWith('{')) |
| return Exception { TypeError, "Member ApplePayAMSUIRequest.engagementRequest is required and must be a JSON-serializable object"_s }; |
| |
| return WTFMove(applePayAMSUIRequest); |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::validateData(Document& document, JSC::JSValue data) |
| { |
| auto requestOrException = convertAndValidateApplePayAMSUIRequest(document, data); |
| if (requestOrException.hasException()) |
| return requestOrException.releaseException(); |
| |
| return { }; |
| } |
| |
| bool ApplePayAMSUIPaymentHandler::handlesIdentifier(const PaymentRequest::MethodIdentifier& identifier) |
| { |
| if (!std::holds_alternative<URL>(identifier)) |
| return false; |
| |
| auto& url = std::get<URL>(identifier); |
| return url.host() == "apple.com"_s && url.path() == "/ams-ui"_s; |
| } |
| |
| bool ApplePayAMSUIPaymentHandler::hasActiveSession(Document& document) |
| { |
| auto* page = document.page(); |
| return page && page->hasActiveApplePayAMSUISession(); |
| } |
| |
| void ApplePayAMSUIPaymentHandler::finishSession(std::optional<bool>&& result) |
| { |
| if (!result) { |
| m_paymentRequest->reject(Exception { AbortError }); |
| return; |
| } |
| |
| m_paymentRequest->accept(std::get<URL>(m_identifier).string(), [success = *result] (JSC::JSGlobalObject& lexicalGlobalObject) -> JSC::Strong<JSC::JSObject> { |
| JSC::JSLockHolder lock { &lexicalGlobalObject }; |
| |
| JSC::VM& vm = lexicalGlobalObject.vm(); |
| auto throwScope = DECLARE_THROW_SCOPE(vm); |
| |
| auto* object = constructEmptyObject(&lexicalGlobalObject); |
| object->putDirect(vm, JSC::Identifier::fromString(vm, "success"_s), JSC::jsBoolean(success)); |
| |
| RETURN_IF_EXCEPTION(throwScope, { }); |
| |
| return { vm, object }; |
| }); |
| } |
| |
| ApplePayAMSUIPaymentHandler::ApplePayAMSUIPaymentHandler(Document& document, const PaymentRequest::MethodIdentifier& identifier, PaymentRequest& paymentRequest) |
| : ContextDestructionObserver { &document } |
| , m_identifier { identifier } |
| , m_paymentRequest { paymentRequest } |
| { |
| ASSERT(handlesIdentifier(m_identifier)); |
| } |
| |
| Document& ApplePayAMSUIPaymentHandler::document() const |
| { |
| ASSERT(is<Document>(scriptExecutionContext())); |
| return downcast<Document>(*scriptExecutionContext()); |
| } |
| |
| Page& ApplePayAMSUIPaymentHandler::page() const |
| { |
| ASSERT(document().page()); |
| return *document().page(); |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::convertData(Document& document, JSC::JSValue data) |
| { |
| auto requestOrException = convertAndValidateApplePayAMSUIRequest(document, data); |
| if (requestOrException.hasException()) |
| return requestOrException.releaseException(); |
| |
| m_applePayAMSUIRequest = requestOrException.releaseReturnValue(); |
| return { }; |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::show(Document& document) |
| { |
| ASSERT(m_applePayAMSUIRequest); |
| |
| if (!page().startApplePayAMSUISession(document, *this, *m_applePayAMSUIRequest)) |
| return Exception { AbortError }; |
| |
| return { }; |
| } |
| |
| void ApplePayAMSUIPaymentHandler::hide() |
| { |
| page().abortApplePayAMSUISession(*this); |
| } |
| |
| void ApplePayAMSUIPaymentHandler::canMakePayment(Document& document, Function<void(bool)>&& completionHandler) |
| { |
| auto* page = document.page(); |
| completionHandler(page && !page->hasActiveApplePayAMSUISession()); |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::detailsUpdated(PaymentRequest::UpdateReason, String&& /* error */, AddressErrors&&, PayerErrorFields&&, JSC::JSObject* /* paymentMethodErrors */) |
| { |
| ASSERT_NOT_REACHED_WITH_MESSAGE("ApplePayAMSUIPaymentHandler does not need shipping/payment info"); |
| return { }; |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::merchantValidationCompleted(JSC::JSValue&& /* merchantSessionValue */) |
| { |
| ASSERT_NOT_REACHED_WITH_MESSAGE("ApplePayAMSUIPaymentHandler does not need merchant validation"); |
| return { }; |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::complete(Document&, std::optional<PaymentComplete>&&, String&&) |
| { |
| hide(); |
| return { }; |
| } |
| |
| ExceptionOr<void> ApplePayAMSUIPaymentHandler::retry(PaymentValidationErrors&&) |
| { |
| return show(document()); |
| } |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST) |