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