Use Optional::valueOr() instead of Optional::value_or()
[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 "PaymentValidationErrors.h"
57 #include "Settings.h"
58
59 namespace WebCore {
60
61 bool ApplePayPaymentHandler::handlesIdentifier(const PaymentRequest::MethodIdentifier& identifier)
62 {
63     if (!WTF::holds_alternative<URL>(identifier))
64         return false;
65
66     auto& url = WTF::get<URL>(identifier);
67     return url.host() == "apple.com" && url.path() == "/apple-pay";
68 }
69
70 static inline PaymentCoordinator& paymentCoordinator(Document& document)
71 {
72     ASSERT(document.page());
73     return document.page()->paymentCoordinator();
74 }
75
76 bool ApplePayPaymentHandler::hasActiveSession(Document& document)
77 {
78     return WebCore::paymentCoordinator(document).hasActiveSession();
79 }
80
81 ApplePayPaymentHandler::ApplePayPaymentHandler(Document& document, const PaymentRequest::MethodIdentifier& identifier, PaymentRequest& paymentRequest)
82     : ContextDestructionObserver { &document }
83     , m_identifier { identifier }
84     , m_paymentRequest { paymentRequest }
85 {
86     ASSERT(handlesIdentifier(m_identifier));
87 }
88
89 Document& ApplePayPaymentHandler::document() const
90 {
91     return downcast<Document>(*scriptExecutionContext());
92 }
93
94 PaymentCoordinator& ApplePayPaymentHandler::paymentCoordinator() const
95 {
96     return WebCore::paymentCoordinator(document());
97 }
98
99 static ExceptionOr<void> validate(const PaymentCurrencyAmount& amount, const String& expectedCurrency)
100 {
101     if (amount.currency != expectedCurrency)
102         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.") };
103     return { };
104 }
105
106 static ExceptionOr<ApplePaySessionPaymentRequest::LineItem> convertAndValidate(const PaymentItem& item, const String& expectedCurrency)
107 {
108     auto exception = validate(item.amount, expectedCurrency);
109     if (exception.hasException())
110         return exception.releaseException();
111
112     ApplePaySessionPaymentRequest::LineItem lineItem;
113     lineItem.amount = item.amount.value;
114     lineItem.type = item.pending ? ApplePaySessionPaymentRequest::LineItem::Type::Pending : ApplePaySessionPaymentRequest::LineItem::Type::Final;
115     lineItem.label = item.label;
116     return { WTFMove(lineItem) };
117 }
118
119 static ExceptionOr<Vector<ApplePaySessionPaymentRequest::LineItem>> convertAndValidate(const Vector<PaymentItem>& lineItems, const String& expectedCurrency)
120 {
121     Vector<ApplePaySessionPaymentRequest::LineItem> result;
122     result.reserveInitialCapacity(lineItems.size());
123     for (auto& lineItem : lineItems) {
124         auto convertedLineItem = convertAndValidate(lineItem, expectedCurrency);
125         if (convertedLineItem.hasException())
126             return convertedLineItem.releaseException();
127         result.uncheckedAppend(convertedLineItem.releaseReturnValue());
128     }
129     return { WTFMove(result) };
130 }
131
132 static ApplePaySessionPaymentRequest::ContactFields convert(const PaymentOptions& options)
133 {
134     ApplePaySessionPaymentRequest::ContactFields result;
135     result.email = options.requestPayerEmail;
136     result.name = options.requestPayerName;
137     result.phone = options.requestPayerPhone;
138     result.postalAddress = options.requestShipping;
139     return result;
140 }
141
142 static ApplePaySessionPaymentRequest::ShippingType convert(PaymentShippingType type)
143 {
144     switch (type) {
145     case PaymentShippingType::Shipping:
146         return ApplePaySessionPaymentRequest::ShippingType::Shipping;
147     case PaymentShippingType::Delivery:
148         return ApplePaySessionPaymentRequest::ShippingType::Delivery;
149     case PaymentShippingType::Pickup:
150         return ApplePaySessionPaymentRequest::ShippingType::StorePickup;
151     }
152
153     ASSERT_NOT_REACHED();
154     return ApplePaySessionPaymentRequest::ShippingType::Shipping;
155 }
156
157 static ExceptionOr<ApplePaySessionPaymentRequest::ShippingMethod> convertAndValidate(const PaymentShippingOption& shippingOption, const String& expectedCurrency)
158 {
159     auto exception = validate(shippingOption.amount, expectedCurrency);
160     if (exception.hasException())
161         return exception.releaseException();
162
163     ApplePaySessionPaymentRequest::ShippingMethod result;
164     result.amount = shippingOption.amount.value;
165     result.label = shippingOption.label;
166     result.identifier = shippingOption.id;
167     return { WTFMove(result) };
168 }
169
170 ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::JSValue&& data)
171 {
172     if (data.isEmpty())
173         return Exception { TypeError, "Missing payment method data." };
174
175     auto& context = *scriptExecutionContext();
176     auto throwScope = DECLARE_THROW_SCOPE(context.vm());
177     auto applePayRequest = convertDictionary<ApplePayRequest>(*context.execState(), WTFMove(data));
178     if (throwScope.exception())
179         return Exception { ExistingExceptionError };
180
181     m_applePayRequest = WTFMove(applePayRequest);
182     return { };
183 }
184
185 ExceptionOr<void> ApplePayPaymentHandler::show()
186 {
187     auto validatedRequest = convertAndValidate(m_applePayRequest->version, *m_applePayRequest, paymentCoordinator());
188     if (validatedRequest.hasException())
189         return validatedRequest.releaseException();
190
191     ApplePaySessionPaymentRequest request = validatedRequest.releaseReturnValue();
192     request.setRequester(ApplePaySessionPaymentRequest::Requester::PaymentRequest);
193
194     String expectedCurrency = m_paymentRequest->paymentDetails().total.amount.currency;
195     request.setCurrencyCode(expectedCurrency);
196
197     auto total = convertAndValidate(m_paymentRequest->paymentDetails().total, expectedCurrency);
198     ASSERT(!total.hasException());
199     request.setTotal(total.releaseReturnValue());
200
201     auto convertedLineItems = convertAndValidate(m_paymentRequest->paymentDetails().displayItems, expectedCurrency);
202     if (convertedLineItems.hasException())
203         return convertedLineItems.releaseException();
204     request.setLineItems(convertedLineItems.releaseReturnValue());
205
206     request.setRequiredShippingContactFields(convert(m_paymentRequest->paymentOptions()));
207     if (m_paymentRequest->paymentOptions().requestShipping)
208         request.setShippingType(convert(m_paymentRequest->paymentOptions().shippingType));
209
210     auto shippingMethods = computeShippingMethods();
211     if (shippingMethods.hasException())
212         return shippingMethods.releaseException();
213     request.setShippingMethods(shippingMethods.releaseReturnValue());
214
215     auto exception = PaymentRequestValidator::validate(request);
216     if (exception.hasException())
217         return exception.releaseException();
218
219     Vector<URL> linkIconURLs;
220     for (auto& icon : LinkIconCollector { document() }.iconsOfTypes({ LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon }))
221         linkIconURLs.append(icon.url);
222
223     paymentCoordinator().beginPaymentSession(*this, document().url(), linkIconURLs, request);
224     return { };
225 }
226
227 void ApplePayPaymentHandler::hide()
228 {
229     paymentCoordinator().abortPaymentSession();
230 }
231
232 void ApplePayPaymentHandler::canMakePayment(Function<void(bool)>&& completionHandler)
233 {
234     completionHandler(paymentCoordinator().canMakePayments());
235 }
236
237 ExceptionOr<Vector<ApplePaySessionPaymentRequest::ShippingMethod>> ApplePayPaymentHandler::computeShippingMethods()
238 {
239     auto& details = m_paymentRequest->paymentDetails();
240     auto& currency = details.total.amount.currency;
241     auto& shippingOptions = details.shippingOptions;
242
243     Vector<ApplePaySessionPaymentRequest::ShippingMethod> shippingMethods;
244     shippingMethods.reserveInitialCapacity(shippingOptions.size());
245
246     for (auto& shippingOption : shippingOptions) {
247         auto shippingMethod = convertAndValidate(shippingOption, currency);
248         if (shippingMethod.hasException())
249             return shippingMethod.releaseException();
250         shippingMethods.uncheckedAppend(shippingMethod.releaseReturnValue());
251     }
252
253     return WTFMove(shippingMethods);
254 }
255
256 ExceptionOr<ApplePaySessionPaymentRequest::TotalAndLineItems> ApplePayPaymentHandler::computeTotalAndLineItems() const
257 {
258     auto& details = m_paymentRequest->paymentDetails();
259     String currency = details.total.amount.currency;
260
261     auto convertedTotal = convertAndValidate(details.total, currency);
262     if (convertedTotal.hasException())
263         return convertedTotal.releaseException();
264     auto total = convertedTotal.releaseReturnValue();
265
266     auto convertedLineItems = convertAndValidate(details.displayItems, currency);
267     if (convertedLineItems.hasException())
268         return convertedLineItems.releaseException();
269     auto lineItems = convertedLineItems.releaseReturnValue();
270
271     if (!m_selectedPaymentMethodType)
272         return ApplePaySessionPaymentRequest::TotalAndLineItems { WTFMove(total), WTFMove(lineItems) };
273
274     auto& modifiers = details.modifiers;
275     auto& serializedModifierData = m_paymentRequest->serializedModifierData();
276     ASSERT(modifiers.size() == serializedModifierData.size());
277     for (size_t i = 0; i < modifiers.size(); ++i) {
278         auto convertedIdentifier = convertAndValidatePaymentMethodIdentifier(modifiers[i].supportedMethods);
279         if (!convertedIdentifier || !handlesIdentifier(*convertedIdentifier))
280             continue;
281
282         if (serializedModifierData[i].isEmpty())
283             continue;
284
285         auto& execState = *document().execState();
286         auto scope = DECLARE_THROW_SCOPE(execState.vm());
287         JSC::JSValue data;
288         {
289             auto lock = JSC::JSLockHolder { &execState };
290             data = JSONParse(&execState, serializedModifierData[i]);
291             if (scope.exception())
292                 return Exception { ExistingExceptionError };
293         }
294
295         auto applePayModifier = convertDictionary<ApplePayModifier>(execState, WTFMove(data));
296         if (scope.exception())
297             return Exception { ExistingExceptionError };
298
299         if (applePayModifier.paymentMethodType != *m_selectedPaymentMethodType)
300             continue;
301
302         if (modifiers[i].total) {
303             auto totalOverride = convertAndValidate(*modifiers[i].total, currency);
304             if (totalOverride.hasException())
305                 return totalOverride.releaseException();
306             total = totalOverride.releaseReturnValue();
307         }
308
309         auto additionalDisplayItems = convertAndValidate(modifiers[i].additionalDisplayItems, currency);
310         if (additionalDisplayItems.hasException())
311             return additionalDisplayItems.releaseException();
312         lineItems.appendVector(additionalDisplayItems.releaseReturnValue());
313         break;
314     }
315
316     return ApplePaySessionPaymentRequest::TotalAndLineItems { WTFMove(total), WTFMove(lineItems) };
317 }
318
319 static inline void appendShippingContactInvalidError(String&& message, Optional<PaymentError::ContactField> contactField, Vector<PaymentError>& errors)
320 {
321     if (!message.isNull())
322         errors.append({ PaymentError::Code::ShippingContactInvalid, WTFMove(message), WTFMove(contactField) });
323 }
324
325 Vector<PaymentError> ApplePayPaymentHandler::computeErrors(String&& error, AddressErrors&& addressErrors, PayerErrorFields&& payerErrors, JSC::JSObject* paymentMethodErrors) const
326 {
327     Vector<PaymentError> errors;
328
329     if (m_paymentRequest->paymentDetails().shippingOptions.isEmpty())
330         computeAddressErrors(WTFMove(error), WTFMove(addressErrors), errors);
331
332     computePayerErrors(WTFMove(payerErrors), errors);
333
334     auto scope = DECLARE_CATCH_SCOPE(scriptExecutionContext()->vm());
335     auto exception = computePaymentMethodErrors(paymentMethodErrors, errors);
336     if (exception.hasException()) {
337         ASSERT(scope.exception());
338         scope.clearException();
339     }
340
341     return errors;
342 }
343
344 void ApplePayPaymentHandler::computeAddressErrors(String&& error, AddressErrors&& addressErrors, Vector<PaymentError>& errors) const
345 {
346     if (!m_paymentRequest->paymentOptions().requestShipping)
347         return;
348
349     using ContactField = PaymentError::ContactField;
350     appendShippingContactInvalidError(WTFMove(error), WTF::nullopt, errors);
351     appendShippingContactInvalidError(WTFMove(addressErrors.addressLine), ContactField::AddressLines, errors);
352     appendShippingContactInvalidError(WTFMove(addressErrors.city), ContactField::Locality, errors);
353     appendShippingContactInvalidError(WTFMove(addressErrors.country), ContactField::Country, errors);
354     appendShippingContactInvalidError(WTFMove(addressErrors.dependentLocality), ContactField::SubLocality, errors);
355     appendShippingContactInvalidError(WTFMove(addressErrors.phone), ContactField::PhoneNumber, errors);
356     appendShippingContactInvalidError(WTFMove(addressErrors.postalCode), ContactField::PostalCode, errors);
357     appendShippingContactInvalidError(WTFMove(addressErrors.recipient), ContactField::Name, errors);
358     appendShippingContactInvalidError(WTFMove(addressErrors.region), ContactField::AdministrativeArea, errors);
359 }
360
361 void ApplePayPaymentHandler::computePayerErrors(PayerErrorFields&& payerErrors, Vector<PaymentError>& errors) const
362 {
363     auto& options = m_paymentRequest->paymentOptions();
364     using ContactField = PaymentError::ContactField;
365
366     if (options.requestPayerName)
367         appendShippingContactInvalidError(WTFMove(payerErrors.name), ContactField::Name, errors);
368
369     if (options.requestPayerEmail)
370         appendShippingContactInvalidError(WTFMove(payerErrors.email), ContactField::EmailAddress, errors);
371
372     if (options.requestPayerPhone)
373         appendShippingContactInvalidError(WTFMove(payerErrors.phone), ContactField::PhoneNumber, errors);
374 }
375
376 ExceptionOr<void> ApplePayPaymentHandler::computePaymentMethodErrors(JSC::JSObject* paymentMethodErrors, Vector<PaymentError>& errors) const
377 {
378     if (!paymentMethodErrors)
379         return { };
380
381 #if ENABLE(APPLE_PAY_SESSION_V3)
382     auto& context = *scriptExecutionContext();
383     auto throwScope = DECLARE_THROW_SCOPE(context.vm());
384     auto applePayErrors = convert<IDLSequence<IDLInterface<ApplePayError>>>(*context.execState(), paymentMethodErrors);
385     if (throwScope.exception())
386         return Exception { ExistingExceptionError };
387
388     for (auto& applePayError : applePayErrors) {
389         if (applePayError)
390             errors.append({ applePayError->code(), applePayError->message(), applePayError->contactField() });
391     }
392 #else
393     UNUSED_PARAM(errors);
394 #endif
395
396     return { };
397 }
398
399 ExceptionOr<void> ApplePayPaymentHandler::detailsUpdated(PaymentRequest::UpdateReason reason, String&& error, AddressErrors&& addressErrors, PayerErrorFields&& payerErrors, JSC::JSObject* paymentMethodErrors)
400 {
401     using Reason = PaymentRequest::UpdateReason;
402     switch (reason) {
403     case Reason::ShowDetailsResolved:
404         return { };
405     case Reason::ShippingAddressChanged:
406         return shippingAddressUpdated(computeErrors(WTFMove(error), WTFMove(addressErrors), WTFMove(payerErrors), paymentMethodErrors));
407     case Reason::ShippingOptionChanged:
408         return shippingOptionUpdated();
409     case Reason::PaymentMethodChanged:
410         return paymentMethodUpdated();
411     }
412
413     ASSERT_NOT_REACHED();
414     return { };
415 }
416
417 ExceptionOr<void> ApplePayPaymentHandler::merchantValidationCompleted(JSC::JSValue&& merchantSessionValue)
418 {
419     if (!paymentCoordinator().hasActiveSession())
420         return Exception { InvalidStateError };
421
422     if (!merchantSessionValue.isObject())
423         return Exception { TypeError };
424
425     String errorMessage;
426     auto merchantSession = PaymentMerchantSession::fromJS(*document().execState(), asObject(merchantSessionValue), errorMessage);
427     if (!merchantSession)
428         return Exception { TypeError, WTFMove(errorMessage) };
429
430     paymentCoordinator().completeMerchantValidation(*merchantSession);
431     return { };
432 }
433
434 ExceptionOr<void> ApplePayPaymentHandler::shippingAddressUpdated(Vector<PaymentError>&& errors)
435 {
436     ASSERT(m_isUpdating);
437     m_isUpdating = false;
438
439     ShippingContactUpdate update;
440     update.errors = WTFMove(errors);
441
442     auto newShippingMethods = computeShippingMethods();
443     if (newShippingMethods.hasException())
444         return newShippingMethods.releaseException();
445     update.newShippingMethods = newShippingMethods.releaseReturnValue();
446
447     auto newTotalAndLineItems = computeTotalAndLineItems();
448     if (newTotalAndLineItems.hasException())
449         return newTotalAndLineItems.releaseException();
450     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
451
452     paymentCoordinator().completeShippingContactSelection(WTFMove(update));
453     return { };
454 }
455
456 ExceptionOr<void> ApplePayPaymentHandler::shippingOptionUpdated()
457 {
458     ASSERT(m_isUpdating);
459     m_isUpdating = false;
460
461     ShippingMethodUpdate update;
462
463     auto newTotalAndLineItems = computeTotalAndLineItems();
464     if (newTotalAndLineItems.hasException())
465         return newTotalAndLineItems.releaseException();
466     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
467
468     paymentCoordinator().completeShippingMethodSelection(WTFMove(update));
469     return { };
470 }
471
472 ExceptionOr<void> ApplePayPaymentHandler::paymentMethodUpdated()
473 {
474     ASSERT(m_isUpdating);
475     m_isUpdating = false;
476
477     PaymentMethodUpdate update;
478
479     auto newTotalAndLineItems = computeTotalAndLineItems();
480     if (newTotalAndLineItems.hasException())
481         return newTotalAndLineItems.releaseException();
482     update.newTotalAndLineItems = newTotalAndLineItems.releaseReturnValue();
483
484     paymentCoordinator().completePaymentMethodSelection(WTFMove(update));
485     return { };
486 }
487
488 void ApplePayPaymentHandler::complete(Optional<PaymentComplete>&& result)
489 {
490     if (!result) {
491         ASSERT(isFinalStateResult(WTF::nullopt));
492         paymentCoordinator().completePaymentSession(WTF::nullopt);
493         return;
494     }
495
496     PaymentAuthorizationResult authorizationResult;
497     switch (*result) {
498     case PaymentComplete::Fail:
499     case PaymentComplete::Unknown:
500         authorizationResult.status = PaymentAuthorizationStatus::Failure;
501         break;
502     case PaymentComplete::Success:
503         authorizationResult.status = PaymentAuthorizationStatus::Success;
504         break;
505     }
506
507     ASSERT(isFinalStateResult(authorizationResult));
508     paymentCoordinator().completePaymentSession(WTFMove(authorizationResult));
509 }
510
511 ExceptionOr<void> ApplePayPaymentHandler::retry(PaymentValidationErrors&& validationErrors)
512 {
513     Vector<PaymentError> errors;
514
515     computeAddressErrors(WTFMove(validationErrors.error), WTFMove(validationErrors.shippingAddress), errors);
516     computePayerErrors(WTFMove(validationErrors.payer), errors);
517
518     auto exception = computePaymentMethodErrors(validationErrors.paymentMethod.get(), errors);
519     if (exception.hasException())
520         return exception.releaseException();
521
522     // Ensure there is always at least one error to avoid having a final result.
523     if (errors.isEmpty())
524         errors.append({ PaymentError::Code::Unknown, { }, WTF::nullopt });
525
526     PaymentAuthorizationResult authorizationResult { PaymentAuthorizationStatus::Failure, WTFMove(errors) };
527     ASSERT(!isFinalStateResult(authorizationResult));
528     paymentCoordinator().completePaymentSession(WTFMove(authorizationResult));
529     return { };
530 }
531
532 unsigned ApplePayPaymentHandler::version() const
533 {
534     if (!m_applePayRequest)
535         return 0;
536     
537     auto version = m_applePayRequest->version;
538     ASSERT(paymentCoordinator().supportsVersion(version));
539     return version;
540 }
541
542 void ApplePayPaymentHandler::validateMerchant(URL&& validationURL)
543 {
544     if (validationURL.isValid())
545         m_paymentRequest->dispatchEvent(MerchantValidationEvent::create(eventNames().merchantvalidationEvent, WTF::get<URL>(m_identifier).string(), WTFMove(validationURL)).get());
546 }
547
548 static Ref<PaymentAddress> convert(const ApplePayPaymentContact& contact)
549 {
550     return PaymentAddress::create(contact.countryCode, contact.addressLines.valueOr(Vector<String>()), contact.administrativeArea, contact.locality, contact.subLocality, contact.postalCode, String(), String(), contact.localizedName, contact.phoneNumber);
551 }
552
553 template<typename T>
554 static JSC::Strong<JSC::JSObject> toJSDictionary(JSC::ExecState& execState, const T& value)
555 {
556     JSC::JSLockHolder lock { &execState };
557     return { execState.vm(), asObject(toJS<IDLDictionary<T>>(execState, *JSC::jsCast<JSDOMGlobalObject*>(execState.lexicalGlobalObject()), value)) };
558 }
559
560 void ApplePayPaymentHandler::didAuthorizePayment(const Payment& payment)
561 {
562     ASSERT(!m_isUpdating);
563
564     auto applePayPayment = payment.toApplePayPayment(version());
565     auto shippingContact = applePayPayment.shippingContact.valueOr(ApplePayPaymentContact());
566     auto detailsFunction = [applePayPayment = WTFMove(applePayPayment)](JSC::ExecState& execState) {
567         return toJSDictionary(execState, applePayPayment);
568     };
569
570     m_paymentRequest->accept(WTF::get<URL>(m_identifier).string(), WTFMove(detailsFunction), convert(shippingContact), shippingContact.localizedName, shippingContact.emailAddress, shippingContact.phoneNumber);
571 }
572
573 void ApplePayPaymentHandler::didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod& shippingMethod)
574 {
575     ASSERT(!m_isUpdating);
576     m_isUpdating = true;
577
578     m_paymentRequest->shippingOptionChanged(shippingMethod.identifier);
579 }
580
581 void ApplePayPaymentHandler::didSelectShippingContact(const PaymentContact& shippingContact)
582 {
583     ASSERT(!m_isUpdating);
584     m_isUpdating = true;
585
586     m_paymentRequest->shippingAddressChanged(convert(shippingContact.toApplePayPaymentContact(version())));
587 }
588
589 void ApplePayPaymentHandler::didSelectPaymentMethod(const PaymentMethod& paymentMethod)
590 {
591     ASSERT(!m_isUpdating);
592     m_isUpdating = true;
593
594     auto applePayPaymentMethod = paymentMethod.toApplePayPaymentMethod();
595     m_selectedPaymentMethodType = applePayPaymentMethod.type;
596     m_paymentRequest->paymentMethodChanged(WTF::get<URL>(m_identifier).string(), [applePayPaymentMethod = WTFMove(applePayPaymentMethod)](JSC::ExecState& execState) {
597         return toJSDictionary(execState, applePayPaymentMethod);
598     });
599 }
600
601 void ApplePayPaymentHandler::didCancelPaymentSession()
602 {
603     m_paymentRequest->cancel();
604 }
605
606 } // namespace WebCore
607
608 #endif // ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST)