blob: 26b47bacbb85ae1dce84dc6840db26e2d7459e7e [file] [log] [blame]
/*
* Copyright (C) 2016-2019 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.
*/
#import "config.h"
#import "PaymentAuthorizationPresenter.h"
#if USE(PASSKIT) && ENABLE(APPLE_PAY)
#import "WKPaymentAuthorizationDelegate.h"
#import "WebPaymentCoordinatorProxyCocoa.h"
#import <WebCore/PaymentAuthorizationStatus.h>
#import <WebCore/PaymentMerchantSession.h>
#import <WebCore/PaymentMethodUpdate.h>
#import <WebCore/PaymentSummaryItems.h>
#import <pal/cocoa/PassKitSoftLink.h>
SOFT_LINK_FRAMEWORK(Contacts);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressCityKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressCountryKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressISOCountryCodeKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressPostalCodeKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressStateKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressStreetKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressSubAdministrativeAreaKey, NSString *);
SOFT_LINK_CONSTANT(Contacts, CNPostalAddressSubLocalityKey, NSString *);
namespace WebKit {
// FIXME: Rather than having these free functions scattered about, Apple Pay data types should know
// how to convert themselves to and from their platform representations.
static PKPaymentAuthorizationStatus toPKPaymentAuthorizationStatus(WebCore::PaymentAuthorizationStatus status)
{
switch (status) {
case WebCore::PaymentAuthorizationStatus::Success:
return PKPaymentAuthorizationStatusSuccess;
case WebCore::PaymentAuthorizationStatus::Failure:
return PKPaymentAuthorizationStatusFailure;
case WebCore::PaymentAuthorizationStatus::PINRequired:
return PKPaymentAuthorizationStatusPINRequired;
case WebCore::PaymentAuthorizationStatus::PINIncorrect:
return PKPaymentAuthorizationStatusPINIncorrect;
case WebCore::PaymentAuthorizationStatus::PINLockout:
return PKPaymentAuthorizationStatusPINLockout;
}
}
static PKPaymentErrorCode toPKPaymentErrorCode(WebCore::PaymentError::Code code)
{
switch (code) {
case WebCore::PaymentError::Code::Unknown:
return PKPaymentUnknownError;
case WebCore::PaymentError::Code::ShippingContactInvalid:
return PKPaymentShippingContactInvalidError;
case WebCore::PaymentError::Code::BillingContactInvalid:
return PKPaymentBillingContactInvalidError;
case WebCore::PaymentError::Code::AddressUnserviceable:
return PKPaymentShippingAddressUnserviceableError;
}
}
static NSError *toNSError(const WebCore::PaymentError& error)
{
auto userInfo = adoptNS([[NSMutableDictionary alloc] init]);
[userInfo setObject:error.message forKey:NSLocalizedDescriptionKey];
if (error.contactField) {
NSString *pkContactField = nil;
NSString *postalAddressKey = nil;
switch (*error.contactField) {
case WebCore::PaymentError::ContactField::PhoneNumber:
pkContactField = PAL::get_PassKit_PKContactFieldPhoneNumber();
break;
case WebCore::PaymentError::ContactField::EmailAddress:
pkContactField = PAL::get_PassKit_PKContactFieldEmailAddress();
break;
case WebCore::PaymentError::ContactField::Name:
pkContactField = PAL::get_PassKit_PKContactFieldName();
break;
case WebCore::PaymentError::ContactField::PhoneticName:
pkContactField = PAL::get_PassKit_PKContactFieldPhoneticName();
break;
case WebCore::PaymentError::ContactField::PostalAddress:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
break;
case WebCore::PaymentError::ContactField::AddressLines:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressStreetKey();
break;
case WebCore::PaymentError::ContactField::SubLocality:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressSubLocalityKey();
break;
case WebCore::PaymentError::ContactField::Locality:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressCityKey();
break;
case WebCore::PaymentError::ContactField::PostalCode:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressPostalCodeKey();
break;
case WebCore::PaymentError::ContactField::SubAdministrativeArea:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressSubAdministrativeAreaKey();
break;
case WebCore::PaymentError::ContactField::AdministrativeArea:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressStateKey();
break;
case WebCore::PaymentError::ContactField::Country:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressCountryKey();
break;
case WebCore::PaymentError::ContactField::CountryCode:
pkContactField = PAL::get_PassKit_PKContactFieldPostalAddress();
postalAddressKey = getCNPostalAddressISOCountryCodeKey();
break;
}
[userInfo setObject:pkContactField forKey:PAL::get_PassKit_PKPaymentErrorContactFieldUserInfoKey()];
if (postalAddressKey)
[userInfo setObject:postalAddressKey forKey:PAL::get_PassKit_PKPaymentErrorPostalAddressUserInfoKey()];
}
return [NSError errorWithDomain:PAL::get_PassKit_PKPaymentErrorDomain() code:toPKPaymentErrorCode(error.code) userInfo:userInfo.get()];
}
static NSArray *toNSErrors(const Vector<WebCore::PaymentError>& errors)
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:errors.size()];
for (const auto& error : errors) {
if (NSError *nsError = toNSError(error))
[result addObject:nsError];
}
return result;
}
static NSArray *toPKShippingMethods(const Vector<WebCore::ApplePaySessionPaymentRequest::ShippingMethod>& shippingMethods)
{
NSMutableArray *pkShippingMethods = [NSMutableArray arrayWithCapacity:shippingMethods.size()];
for (auto& shippingMethod : shippingMethods)
[pkShippingMethods addObject:toPKShippingMethod(shippingMethod)];
return pkShippingMethods;
}
void PaymentAuthorizationPresenter::completeMerchantValidation(const WebCore::PaymentMerchantSession& merchantSession)
{
ASSERT(platformDelegate());
[platformDelegate() completeMerchantValidation:merchantSession.pkPaymentMerchantSession() error:nil];
}
void PaymentAuthorizationPresenter::completePaymentMethodSelection(const Optional<WebCore::PaymentMethodUpdate>& update)
{
ASSERT(platformDelegate());
if (!update) {
[platformDelegate() completePaymentMethodSelection:nil];
return;
}
[platformDelegate() completePaymentMethodSelection:update->platformUpdate()];
}
void PaymentAuthorizationPresenter::completePaymentSession(const Optional<WebCore::PaymentAuthorizationResult>& result)
{
ASSERT(platformDelegate());
auto status = result ? toPKPaymentAuthorizationStatus(result->status) : PKPaymentAuthorizationStatusSuccess;
NSArray *errors = result ? toNSErrors(result->errors) : @[ ];
[platformDelegate() completePaymentSession:status errors:errors didReachFinalState:WebCore::isFinalStateResult(result)];
}
void PaymentAuthorizationPresenter::completeShippingContactSelection(const Optional<WebCore::ShippingContactUpdate>& update)
{
ASSERT(platformDelegate());
if (!update) {
[platformDelegate() completeShippingContactSelection:nil];
return;
}
// FIXME: WebCore::ShippingContactUpdate should know how to convert itself to a PKPaymentRequestShippingContactUpdate.
auto shippingContactUpdate = adoptNS([PAL::allocPKPaymentRequestShippingContactUpdateInstance() initWithErrors:toNSErrors(update->errors) paymentSummaryItems:WebCore::platformSummaryItems(update->newTotalAndLineItems) shippingMethods:toPKShippingMethods(update->newShippingMethods)]);
[platformDelegate() completeShippingContactSelection:shippingContactUpdate.get()];
}
void PaymentAuthorizationPresenter::completeShippingMethodSelection(const Optional<WebCore::ShippingMethodUpdate>& update)
{
ASSERT(platformDelegate());
if (!update) {
[platformDelegate() completeShippingMethodSelection:nil];
return;
}
// FIXME: WebCore::ShippingMethodUpdate should know how to convert itself to a PKPaymentRequestShippingMethodUpdate.
auto shippingMethodUpdate = adoptNS([PAL::allocPKPaymentRequestShippingMethodUpdateInstance() initWithPaymentSummaryItems:WebCore::platformSummaryItems(update->newTotalAndLineItems)]);
[platformDelegate() completeShippingMethodSelection:shippingMethodUpdate.get()];
}
} // namespace WebKit
#endif // USE(PASSKIT) && ENABLE(APPLE_PAY)