/* * Copyright (C) 2015, 2016 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 "PaymentRequestValidator.h" #if ENABLE(APPLE_PAY) #include "ExceptionCode.h" #include "PaymentRequest.h" #include #include namespace WebCore { static ExceptionOr validateCountryCode(const String&); static ExceptionOr validateCurrencyCode(const String&); static ExceptionOr validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities&); static ExceptionOr validateSupportedNetworks(const Vector&); static ExceptionOr validateShippingMethods(const Vector&); static ExceptionOr validateShippingMethod(const PaymentRequest::ShippingMethod&); ExceptionOr PaymentRequestValidator::validate(const PaymentRequest& paymentRequest) { auto validatedCountryCode = validateCountryCode(paymentRequest.countryCode()); if (validatedCountryCode.hasException()) return validatedCountryCode.releaseException(); auto validatedCurrencyCode = validateCurrencyCode(paymentRequest.currencyCode()); if (validatedCurrencyCode.hasException()) return validatedCurrencyCode.releaseException(); auto validatedSupportedNetworks = validateSupportedNetworks(paymentRequest.supportedNetworks()); if (validatedSupportedNetworks.hasException()) return validatedSupportedNetworks.releaseException(); auto validatedMerchantCapabilities = validateMerchantCapabilities(paymentRequest.merchantCapabilities()); if (validatedMerchantCapabilities.hasException()) return validatedMerchantCapabilities.releaseException(); auto validatedTotal = validateTotal(paymentRequest.total()); if (validatedTotal.hasException()) return validatedTotal.releaseException(); auto validatedShippingMethods = validateShippingMethods(paymentRequest.shippingMethods()); if (validatedShippingMethods.hasException()) return validatedShippingMethods.releaseException(); return { }; } ExceptionOr PaymentRequestValidator::validateTotal(const PaymentRequest::LineItem& total) { if (!total.label) return Exception { TypeError, "Missing total label." }; if (!total.amount) return Exception { TypeError, "Missing total amount." }; if (*total.amount <= 0) return Exception { TypeError, "Total amount must be greater than zero." }; if (*total.amount > 10000000000) return Exception { TypeError, "Total amount is too big." }; return { }; } static ExceptionOr validateCountryCode(const String& countryCode) { if (!countryCode) return Exception { TypeError, "Missing country code." }; for (auto *countryCodePtr = uloc_getISOCountries(); *countryCodePtr; ++countryCodePtr) { if (countryCode == *countryCodePtr) return { }; } return Exception { TypeError, makeString("\"" + countryCode, "\" is not a valid country code.") }; } static ExceptionOr validateCurrencyCode(const String& currencyCode) { if (!currencyCode) return Exception { TypeError, "Missing currency code." }; UErrorCode errorCode = U_ZERO_ERROR; auto currencyCodes = std::unique_ptr(ucurr_openISOCurrencies(UCURR_ALL, &errorCode), uenum_close); int32_t length; while (auto *currencyCodePtr = uenum_next(currencyCodes.get(), &length, &errorCode)) { if (currencyCodePtr == currencyCode) return { }; } return Exception { TypeError, makeString("\"" + currencyCode, "\" is not a valid currency code.") }; } static ExceptionOr validateMerchantCapabilities(const PaymentRequest::MerchantCapabilities& merchantCapabilities) { if (!merchantCapabilities.supports3DS && !merchantCapabilities.supportsEMV && !merchantCapabilities.supportsCredit && !merchantCapabilities.supportsDebit) return Exception { TypeError, "Missing merchant capabilities." }; return { }; } static ExceptionOr validateSupportedNetworks(const Vector& supportedNetworks) { if (supportedNetworks.isEmpty()) return Exception { TypeError, "Missing supported networks." }; return { }; } static ExceptionOr validateShippingMethod(const PaymentRequest::ShippingMethod& shippingMethod) { if (shippingMethod.amount < 0) return Exception { TypeError, "Shipping method amount must be greater than or equal to zero." }; return { }; } static ExceptionOr validateShippingMethods(const Vector& shippingMethods) { for (const auto& shippingMethod : shippingMethods) { auto validatedShippingMethod = validateShippingMethod(shippingMethod); if (validatedShippingMethod.hasException()) return validatedShippingMethod.releaseException(); } return { }; } } #endif