56055f71381cdf0dea5304b4d4db76c42c9f6a47
[WebKit-https.git] / Source / WebCore / Modules / applepay / paymentrequest / ApplePayPaymentHandler.cpp
1 /*
2  * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ApplePayPaymentHandler.h"
28
29 #if ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST)
30
31 #include "AddressErrors.h"
32 #include "ApplePayContactField.h"
33 #include "ApplePayMerchantCapability.h"
34 #include "ApplePayModifier.h"
35 #include "ApplePayPayment.h"
36 #include "ApplePaySessionPaymentRequest.h"
37 #include "Document.h"
38 #include "EventNames.h"
39 #include "Frame.h"
40 #include "JSApplePayError.h"
41 #include "JSApplePayPayment.h"
42 #include "JSApplePayPaymentMethod.h"
43 #include "JSApplePayRequest.h"
44 #include "LinkIconCollector.h"
45 #include "MerchantValidationEvent.h"
46 #include "Page.h"
47 #include "PayerErrorFields.h"
48 #include "Payment.h"
49 #include "PaymentAuthorizationStatus.h"
50 #include "PaymentContact.h"
51 #include "PaymentCoordinator.h"
52 #include "PaymentMerchantSession.h"
53 #include "PaymentMethod.h"
54 #include "PaymentRequestValidator.h"
55 #include "PaymentResponse.h"
56 #include "Settings.h"
57
58 namespace WebCore {
59
60 bool ApplePayPaymentHandler::handlesIdentifier(const PaymentRequest::MethodIdentifier& identifier)
61 {
62     if (!WTF::holds_alternative<URL>(identifier))
63         return false;
64
65     auto& url = WTF::get<URL>(identifier);
66     return url.host() == "apple.com" && url.path() == "/apple-pay";
67 }
68
69 static inline PaymentCoordinator& paymentCoordinator(Document& document)
70 {
71     ASSERT(document.page());
72     return document.page()->paymentCoordinator();
73 }
74
75 bool ApplePayPaymentHandler::hasActiveSession(Document& document)
76 {
77     return WebCore::paymentCoordinator(document).hasActiveSession();
78 }
79
80 ApplePayPaymentHandler::ApplePayPaymentHandler(Document& document, const PaymentRequest::MethodIdentifier& identifier, PaymentRequest& paymentRequest)
81     : ContextDestructionObserver { &document }
82     , m_identifier { identifier }
83     , m_paymentRequest { paymentRequest }
84 {
85     ASSERT(handlesIdentifier(m_identifier));
86 }
87
88 Document& ApplePayPaymentHandler::document() const
89 {
90     return downcast<Document>(*scriptExecutionContext());
91 }
92
93 PaymentCoordinator& ApplePayPaymentHandler::paymentCoordinator() const
94 {
95     return WebCore::paymentCoordinator(document());
96 }
97
98 static ExceptionOr<void> validate(const PaymentCurrencyAmount& amount, const String& expectedCurrency)
99 {
100     if (amount.currency != expectedCurrency)
101         return Exception { TypeError, makeString("\"", amount.currency, "\" does not match the expected currency of \"", expectedCurrency, "\". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code.") };
102     return { };
103 }
104
105 static ExceptionOr<ApplePaySessionPaymentRequest::LineItem> convertAndValidate(const PaymentItem& item, const String& expectedCurrency)
106 {
107     auto exception = validate(item.amount, expectedCurrency);
108     if (exception.hasException())
109         return exception.releaseException();
110
111     ApplePaySessionPaymentRequest::LineItem lineItem;
112     lineItem.amount = item.amount.value;
113     lineItem.type = item.pending ? ApplePaySessionPaymentRequest::LineItem::Type::Pending : ApplePaySessionPaymentRequest::LineItem::Type::Final;
114     lineItem.label = item.label;
115     return { WTFMove(lineItem) };
116 }
117
118 static ExceptionOr<Vector<ApplePaySessionPaymentRequest::LineItem>> convertAndValidate(const Vector<PaymentItem>& lineItems, const String& expectedCurrency)
119 {
120     Vector<ApplePaySessionPaymentRequest::LineItem> result;
121     result.reserveInitialCapacity(lineItems.size());
122     for (auto& lineItem : lineItems) {
123         auto convertedLineItem = convertAndValidate(lineItem, expectedCurrency);
124         if (convertedLineItem.hasException())
125             return convertedLineItem.releaseException();
126         result.uncheckedAppend(convertedLineItem.releaseReturnValue());
127     }
128     return { WTFMove(result) };
129 }
130
131 static ApplePaySessionPaymentRequest::ContactFields convert(const PaymentOptions& options)
132 {
133     ApplePaySessionPaymentRequest::ContactFields result;
134     result.email = options.requestPayerEmail;
135     result.name = options.requestPayerName;
136     result.phone = options.requestPayerPhone;
137     result.postalAddress = options.requestShipping;
138     return result;
139 }
140
141 static ApplePaySessionPaymentRequest::ShippingType convert(PaymentShippingType type)
142 {
143     switch (type) {
144     case PaymentShippingType::Shipping:
145         return ApplePaySessionPaymentRequest::ShippingType::Shipping;
146     case PaymentShippingType::Delivery:
147         return ApplePaySessionPaymentRequest::ShippingType::Delivery;
148     case PaymentShippingType::Pickup:
149         return ApplePaySessionPaymentRequest::ShippingType::StorePickup;
150     }
151
152     ASSERT_NOT_REACHED();
153     return ApplePaySessionPaymentRequest::ShippingType::Shipping;
154 }
155
156 static ExceptionOr<ApplePaySessionPaymentRequest::ShippingMethod> convertAndValidate(const PaymentShippingOption& shippingOption, const String& expectedCurrency)
157 {
158     auto exception = validate(shippingOption.amount, expectedCurrency);
159     if (exception.hasException())
160         return exception.releaseException();
161
162     ApplePaySessionPaymentRequest::ShippingMethod result;
163     result.amount = shippingOption.amount.value;
164     result.label = shippingOption.label;
165     result.identifier = shippingOption.id;
166     return { WTFMove(result) };
167 }
168
169 ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::JSValue&& data)
170 {
171     auto& context = *scriptExecutionContext();
172     auto throwScope = DECLARE_THROW_SCOPE(context.vm());
173     auto applePayRequest = convertDictionary<ApplePayRequest>(*context.execState(), WTFMove(data));
174     if (throwScope.exception())
175         return Exception { ExistingExceptionError };
176
177     m_applePayRequest = WTFMove(applePayRequest);
178     return { };
179 }
180
181 ExceptionOr<void> ApplePayPaymentHandler::show()
182 {
183     auto validatedRequest = convertAndValidate(m_applePayRequest->version, *m_applePayRequest, paymentCoordinator());
184     if (validatedRequest.hasException())
185         return validatedRequest.releaseException();
186
187     ApplePaySessionPaymentRequest request = validatedRequest.releaseReturnValue();
188     request.setRequester(ApplePaySessionPaymentRequest::Requester::PaymentRequest);
189
190     String expectedCurrency = m_paymentRequest->paymentDetails().total.amount.currency;
191     request.setCurrencyCode(expectedCurrency);
192
193     auto total = convertAndValidate(m_paymentRequest->paymentDetails().total, expectedCurrency);
194     ASSERT(!total.hasException());
195     request.setTotal(total.releaseReturnValue());
196
197     auto convertedLineItems = convertAndValidate(m_paymentRequest->paymentDetails().displayItems, expectedCurrency);
198     if (convertedLineItems.hasException())
199         return convertedLineItems.releaseException();
200     request.setLineItems(convertedLineItems.releaseReturnValue());
201
202     request.setRequiredShippingContactFields(convert(m_paymentRequest->paymentOptions()));
203     if (m_paymentRequest->paymentOptions().requestShipping)
204         request.setShippingType(convert(m_paymentRequest->paymentOptions().shippingType));
205
206     auto shippingMethods = computeShippingMethods();
207     if (shippingMethods.hasException())
208         return shippingMethods.releaseException();
209     request.setShippingMethods(shippingMethods.releaseReturnValue());
210
211     auto exception = PaymentRequestValidator::validate(request);
212     if (exception.hasException())
213         return exception.releaseException();
214
215     Vector<URL> linkIconURLs;
216     for (auto& icon : LinkIconCollector { document() }.iconsOfTypes({ LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon }))
217         linkIconURLs.append(icon.url);
218
219     paymentCoordinator().beginPaymentSession(*this, document().url(), linkIconURLs, request);
220     return { };
221 }
222
223 void ApplePayPaymentHandler::hide()
224 {
225     paymentCoordinator().abortPaymentSession();
226 }
227
228 static bool shouldDiscloseApplePayCapability(Document& document)
229 {
230     auto* page = document.page();
231     if (!page || page->usesEphemeralSession())
232         return false;
233
234     return document.settings().applePayCapabilityDisclosureAllowed();
235 }
236
237 void ApplePayPaymentHandler::canMakePayment(Function<void(bool)>&& completionHandler)
238 {
239     if (!shouldDiscloseApplePayCapability(document())) {
240         completionHandler(paymentCoordinator().canMakePayments());
241         return;
242     }
243
244     paymentCoordinator().canMakePaymentsWithActiveCard(m_applePayRequest->merchantIdentifier, document().domain(), WTFMove(completionHandler));
245 }
246     
247 ExceptionOr<Vector<ApplePaySessionPaymentRequest::ShippingMethod>> ApplePayPaymentHandler::computeShippingMethods()
248 {
249     auto& details = m_paymentRequest->paymentDetails();
250     auto& currency = details.total.amount.currency;
251     auto& shippingOptions = details.shippingOptions;
252
253     Vector<ApplePaySessionPaymentRequest::ShippingMethod> shippingMethods;
254     shippingMethods.reserveInitialCapacity(shippingOptions.size());
255
256     for (auto& shippingOption : shippingOptions) {
257         auto shippingMethod = convertAndValidate(shippingOption, currency);
258         if (shippingMethod.hasException())
259             return shippingMethod.releaseException();
260         shippingMethods.uncheckedAppend(shippingMethod.releaseReturnValue());
261     }
262
263     return WTFMove(shippingMethods);
264 }
265
266 ExceptionOr<ApplePaySessionPaymentRequest::TotalAndLineItems> ApplePayPaymentHandler::computeTotalAndLineItems()
267 {
268     auto& details = m_paymentRequest->paymentDetails();
269     String currency = details.total.amount.currency;
270
271     auto convertedTotal = convertAndValidate(details.total, currency);
272     if (convertedTotal.hasException())
273         return convertedTotal.releaseException();
274     auto total = convertedTotal.releaseReturnValue();
275
276     auto convertedLineItems = convertAndValidate(details.displayItems, currency);
277     if (convertedLineItems.hasException())
278         return convertedLineItems.releaseException();
279     auto lineItems = convertedLineItems.releaseReturnValue();
280
281     if (!m_selectedPaymentMethodType)
282         return ApplePaySessionPaymentRequest::TotalAndLineItems { WTFMove(total), WTFMove(lineItems) };
283
284     auto& modifiers = details.modifiers;
285     auto& serializedModifierData = m_paymentRequest->serializedModifierData();
286     ASSERT(modifiers.size() == serializedModifierData.size());
287     for (size_t i = 0; i < modifiers.size(); ++i) {
288         auto convertedIdentifier = convertAndValidatePaymentMethodIdentifier(modifiers[i].supportedMethods);
289         if (!convertedIdentifier || !handlesIdentifier(*convertedIdentifier))
290             continue;
291
292         if (serializedModifierData[i].isEmpty())
293             continue;
294
295         auto& execState = *document().execState();
296         auto scope = DECLARE_THROW_SCOPE(execState.vm());
297         JSC::JSValue data;
298         {
299             auto lock = JSC::JSLockHolder { &execState };
300             data = JSONParse(&execState, serializedModifierData[i]);
301             if (scope.exception())
302                 return Exception { ExistingExceptionError };
303         }
304
305         auto applePayModifier = convertDictionary<ApplePayModifier>(execState, WTFMove(data));
306         if (scope.exception())
307             return Exception { ExistingExceptionError };
308
309         if (applePayModifier.paymentMethodType != *m_selectedPaymentMethodType)
310             continue;
311
312         if (modifiers[i].total) {
313             auto totalOverride = convertAndValidate(*modifiers[i].total, currency);
314             if (totalOverride.hasException())
315                 return totalOverride.releaseException();
316             total = totalOverride.releaseReturnValue();
317         }
318
319         auto additionalDisplayItems = convertAndValidate(modifiers[i].additionalDisplayItems, currency);
320         if (additionalDisplayItems.hasException())
321             return additionalDisplayItems.releaseException();
322         lineItems.appendVector(additionalDisplayItems.releaseReturnValue());
323         break;
324     }
325
326     return ApplePaySessionPaymentRequest::TotalAndLineItems { WTFMove(total), WTFMove(lineItems) };
327 }
328
329 static inline void appendShippingContactInvalidError(String&& message, std::optional<PaymentError::ContactField> contactField, Vector<PaymentError>& errors)
330 {
331     if (!message.isNull())
332         errors.append({ PaymentError::Code::ShippingContactInvalid, WTFMove(message), WTFMove(contactField) });
333 }
334
335 Vector<PaymentError> ApplePayPaymentHandler::computeErrors(String&& error, AddressErrors&& addressErrors, PayerErrorFields&& payerErrors, JSC::JSObject* paymentMethodErrors) const
336 {
337     Vector<PaymentError> errors;
338
339     auto& options = m_paymentRequest->paymentOptions();
340     using ContactField = PaymentError::ContactField;
341
342     if (options.requestShipping && m_paymentRequest->paymentDetails().shippingOptions.isEmpty()) {
343         appendShippingContactInvalidError(WTFMove(error), std::nullopt, errors);
344         appendShippingContactInvalidError(WTFMove(addressErrors.addressLine), ContactField::AddressLines, errors);
345         appendShippingContactInvalidError(WTFMove(addressErrors.city), ContactField::Locality, errors);
346         appendShippingContactInvalidError(WTFMove(addressErrors.country), ContactField::Country, errors);
347         appendShippingContactInvalidError(WTFMove(addressErrors.dependentLocality), ContactField::SubLocality, errors);
348         appendShippingContactInvalidError(WTFMove(addressErrors.phone), ContactField::PhoneNumber, errors);
349         appendShippingContactInvalidError(WTFMove(addressErrors.postalCode), ContactField::PostalCode, errors);
350         appendShippingContactInvalidError(WTFMove(addressErrors.recipient), ContactField::Name, errors);
351         appendShippingContactInvalidError(WTFMove(addressErrors.region), ContactField::AdministrativeArea, errors);
352     }
353
354     if (options.requestPayerName)
355         appendShippingContactInvalidError(WTFMove(payerErrors.name), ContactField::Name, errors);
356
357     if (options.requestPayerEmail)
358         appendShippingContactInvalidError(WTFMove(payerErrors.email), ContactField::EmailAddress, errors);
359
360     if (options.requestPayerPhone)
361         appendShippingContactInvalidError(WTFMove(payerErrors.phone), ContactField::PhoneNumber, errors);
362
363 #if ENABLE(APPLE_PAY_SESSION_V3)
364     if (paymentMethodErrors) {
365         auto& context = *scriptExecutionContext();
366         auto throwScope = DECLARE_THROW_SCOPE(context.vm());
367         auto applePayErrors = convert<IDLSequence<IDLInterface<ApplePayError>>>(*context.execState(), paymentMethodErrors);
368         if (!throwScope.exception()) {
369             for (auto& applePayError : applePayErrors) {
370                 if (applePayError)
371                     errors.append({ applePayError->code(), applePayError->message(), applePayError->contactField() });
372             }
373         }
374     }
375 #else
376     UNUSED_PARAM(paymentMethodErrors);
377 #endif
378
379     return errors;
380 }
381
382 ExceptionOr<void> ApplePayPaymentHandler::detailsUpdated(PaymentRequest::UpdateReason reason, String&& error, AddressErrors&& addressErrors, PayerErrorFields&& payerErrors, JSC::JSObject* paymentMethodErrors)
383 {
384     using Reason = PaymentRequest::UpdateReason;
385     switch (reason) {
386     case Reason::ShowDetailsResolved:
387         return { };
388     case Reason::ShippingAddressChanged:
389         return shippingAddressUpdated(computeErrors(WTFMove(error), WTFMove(addressErrors), WTFMove(payerErrors), paymentMethodErrors));
390     case Reason::ShippingOptionChanged:
391         return shippingOptionUpdated();
392     case Reason::PaymentMethodChanged:
393         return paymentMethodUpdated();
394     }
395
396     ASSERT_NOT_REACHED();
397     return { };
398 }
399
400 ExceptionOr<void> ApplePayPaymentHandler::merchantValidationCompleted(JSC::JSValue&& merchantSessionValue)
401 {
402     if (!paymentCoordinator().hasActiveSession())
403         return Exception { InvalidStateError };
404
405     if (!merchantSessionValue.isObject())
406         return Exception { TypeError };
407
408     String errorMessage;
409     auto merchantSession = PaymentMerchantSession::fromJS(*document().execState(), asObject(merchantSessionValue), errorMessage);
410     if (!merchantSession)
411         return Exception { TypeError, WTFMove(errorMessage) };
412
413     paymentCoordinator().completeMerchantValidation(*merchantSession);
414     return { };
415 }
416
417 ExceptionOr<void> ApplePayPaymentHandler::shippingAddressUpdated(Vector<PaymentError>&& errors)
418 {
419     ASSERT(m_isUpdating);
420     m_isUpdating = false;
421
422     ShippingContactUpdate update;
423     update.errors = WTFMove(errors);
424
425     auto newShippingMethods = computeShippingMethods();
426     if (newShippingMethods.hasException())
427         return newShippingMethods.releaseException();
428     update.newShippingMethods = newShippingMethods.releaseReturnValue();
429
430     auto newTotalAndLineItems = computeTotalAndLineItems();
431     if (newTotalAndLineItems.hasException())
432         return newTotalAndLineItems.releaseException();
433     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
434
435     paymentCoordinator().completeShippingContactSelection(WTFMove(update));
436     return { };
437 }
438
439 ExceptionOr<void> ApplePayPaymentHandler::shippingOptionUpdated()
440 {
441     ASSERT(m_isUpdating);
442     m_isUpdating = false;
443
444     ShippingMethodUpdate update;
445
446     auto newTotalAndLineItems = computeTotalAndLineItems();
447     if (newTotalAndLineItems.hasException())
448         return newTotalAndLineItems.releaseException();
449     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
450
451     paymentCoordinator().completeShippingMethodSelection(WTFMove(update));
452     return { };
453 }
454
455 ExceptionOr<void> ApplePayPaymentHandler::paymentMethodUpdated()
456 {
457     ASSERT(m_isUpdating);
458     m_isUpdating = false;
459
460     PaymentMethodUpdate update;
461
462     auto newTotalAndLineItems = computeTotalAndLineItems();
463     if (newTotalAndLineItems.hasException())
464         return newTotalAndLineItems.releaseException();
465     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
466
467     paymentCoordinator().completePaymentMethodSelection(WTFMove(update));
468     return { };
469 }
470
471 void ApplePayPaymentHandler::complete(std::optional<PaymentComplete>&& result)
472 {
473     if (!result) {
474         paymentCoordinator().completePaymentSession(std::nullopt);
475         return;
476     }
477
478     PaymentAuthorizationResult authorizationResult;
479     switch (*result) {
480     case PaymentComplete::Fail:
481     case PaymentComplete::Unknown:
482         authorizationResult.status = PaymentAuthorizationStatus::Failure;
483         break;
484     case PaymentComplete::Success:
485         authorizationResult.status = PaymentAuthorizationStatus::Success;
486         break;
487     }
488
489     paymentCoordinator().completePaymentSession(WTFMove(authorizationResult));
490 }
491
492 unsigned ApplePayPaymentHandler::version() const
493 {
494     if (!m_applePayRequest)
495         return 0;
496     
497     auto version = m_applePayRequest->version;
498     ASSERT(paymentCoordinator().supportsVersion(version));
499     return version;
500 }
501
502 void ApplePayPaymentHandler::validateMerchant(URL&& validationURL)
503 {
504     if (validationURL.isValid())
505         m_paymentRequest->dispatchEvent(MerchantValidationEvent::create(eventNames().merchantvalidationEvent, WTFMove(validationURL)).get());
506 }
507
508 static Ref<PaymentAddress> convert(const ApplePayPaymentContact& contact)
509 {
510     return PaymentAddress::create(contact.countryCode, contact.addressLines.value_or(Vector<String>()), contact.administrativeArea, contact.locality, contact.subLocality, contact.postalCode, String(), String(), contact.localizedName, contact.phoneNumber);
511 }
512
513 template<typename T>
514 static JSC::Strong<JSC::JSObject> toJSDictionary(JSC::ExecState& execState, const T& value)
515 {
516     JSC::JSLockHolder lock { &execState };
517     return { execState.vm(), asObject(toJS<IDLDictionary<T>>(execState, *JSC::jsCast<JSDOMGlobalObject*>(execState.lexicalGlobalObject()), value)) };
518 }
519
520 void ApplePayPaymentHandler::didAuthorizePayment(const Payment& payment)
521 {
522     ASSERT(!m_isUpdating);
523
524     auto applePayPayment = payment.toApplePayPayment(version());
525     auto shippingContact = applePayPayment.shippingContact.value_or(ApplePayPaymentContact());
526     auto detailsFunction = [applePayPayment = WTFMove(applePayPayment)](JSC::ExecState& execState) {
527         return toJSDictionary(execState, applePayPayment);
528     };
529
530     m_paymentRequest->accept(WTF::get<URL>(m_identifier).string(), WTFMove(detailsFunction), convert(shippingContact), shippingContact.localizedName, shippingContact.emailAddress, shippingContact.phoneNumber);
531 }
532
533 void ApplePayPaymentHandler::didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod& shippingMethod)
534 {
535     ASSERT(!m_isUpdating);
536     m_isUpdating = true;
537
538     m_paymentRequest->shippingOptionChanged(shippingMethod.identifier);
539 }
540
541 void ApplePayPaymentHandler::didSelectShippingContact(const PaymentContact& shippingContact)
542 {
543     ASSERT(!m_isUpdating);
544     m_isUpdating = true;
545
546     m_paymentRequest->shippingAddressChanged(convert(shippingContact.toApplePayPaymentContact(version())));
547 }
548
549 void ApplePayPaymentHandler::didSelectPaymentMethod(const PaymentMethod& paymentMethod)
550 {
551     ASSERT(!m_isUpdating);
552     m_isUpdating = true;
553
554     auto applePayPaymentMethod = paymentMethod.toApplePayPaymentMethod();
555     m_selectedPaymentMethodType = applePayPaymentMethod.type;
556     m_paymentRequest->paymentMethodChanged(WTF::get<URL>(m_identifier).string(), [applePayPaymentMethod = WTFMove(applePayPaymentMethod)](JSC::ExecState& execState) {
557         return toJSDictionary(execState, applePayPaymentMethod);
558     });
559 }
560
561 void ApplePayPaymentHandler::didCancelPaymentSession()
562 {
563     m_paymentRequest->cancel();
564 }
565
566 } // namespace WebCore
567
568 #endif // ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST)