Changeset 223163 in webkit


Ignore:
Timestamp:
Oct 10, 2017 7:57:12 PM (7 years ago)
Author:
aestes@apple.com
Message:

[Payment Request] Validate that all PaymentCurrencyAmounts use the same currency code when using Apple Pay
https://bugs.webkit.org/show_bug.cgi?id=178150

Reviewed by Tim Horton.

Source/WebCore:

Apple Pay requires a single currency code, but the Payment Request API allows the client to
specify a currency code for each PaymentCurrencyAmount.

Instead of having a required currencyCode property on ApplePayRequest and ignoring the
currency property on PaymentCurrencyAmount, validate that all PaymentCurrencyAmounts use the
same currency code and use that as ApplePaySessionPaymentRequest's currencyCode.

Added test cases to http/tests/ssl/applepay/PaymentRequest.https.html.

  • Modules/applepay/ApplePayPaymentRequest.h:
  • Modules/applepay/ApplePayPaymentRequest.idl:
  • Modules/applepay/ApplePayRequestBase.cpp:

(WebCore::convertAndValidate):

  • Modules/applepay/ApplePayRequestBase.h:
  • Modules/applepay/ApplePayRequestBase.idl:
  • Modules/applepay/ApplePaySession.cpp:

(WebCore::convertAndValidate):

  • Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:

(WebCore::validate):
(WebCore::convertAndValidate):
(WebCore::ApplePayPaymentHandler::show):

  • Modules/applepay/paymentrequest/ApplePayRequest.idl:

LayoutTests:

  • http/tests/paymentrequest/payment-request-abort-method.https.html:
  • http/tests/paymentrequest/payment-request-canmakepayment-method.https.html:
  • http/tests/paymentrequest/payment-request-show-method.https.html:
  • http/tests/ssl/applepay/PaymentRequest.https-expected.txt:
  • http/tests/ssl/applepay/PaymentRequest.https.html:
Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r223160 r223163  
     12017-10-10  Andy Estes  <aestes@apple.com>
     2
     3        [Payment Request] Validate that all PaymentCurrencyAmounts use the same currency code when using Apple Pay
     4        https://bugs.webkit.org/show_bug.cgi?id=178150
     5
     6        Reviewed by Tim Horton.
     7
     8        * http/tests/paymentrequest/payment-request-abort-method.https.html:
     9        * http/tests/paymentrequest/payment-request-canmakepayment-method.https.html:
     10        * http/tests/paymentrequest/payment-request-show-method.https.html:
     11        * http/tests/ssl/applepay/PaymentRequest.https-expected.txt:
     12        * http/tests/ssl/applepay/PaymentRequest.https.html:
     13
    1142017-10-10  Andy Estes  <aestes@apple.com>
    215
  • trunk/LayoutTests/http/tests/paymentrequest/payment-request-abort-method.https.html

    r223160 r223163  
    2323        supportedNetworks: ['visa', 'masterCard'],
    2424        countryCode: 'US',
    25         currencyCode: 'USD',
    2625    },
    2726});
  • trunk/LayoutTests/http/tests/paymentrequest/payment-request-canmakepayment-method.https.html

    r223160 r223163  
    1717        supportedNetworks: ["visa", "masterCard"],
    1818        countryCode: "US",
    19         currencyCode: "USD",
    2019    }
    2120});
  • trunk/LayoutTests/http/tests/paymentrequest/payment-request-show-method.https.html

    r223160 r223163  
    1818        supportedNetworks: ['visa', 'masterCard'],
    1919        countryCode: 'US',
    20         currencyCode: 'USD',
    2120    },
    2221});
  • trunk/LayoutTests/http/tests/ssl/applepay/PaymentRequest.https-expected.txt

    r222921 r223163  
    2929PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "7" is not a valid country code..
    3030
    31 Testing ApplePayRequest.currencyCode
    32 
    33 SETUP: paymentMethod = validPaymentMethod(); delete paymentMethod.data.currencyCode;
    34 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.currencyCode is required and must be an instance of DOMString.
    35 
    36 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = 'invalid';
    37 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "invalid" is not a valid currency code..
    38 
    39 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = '';
    40 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "" is not a valid currency code..
    41 
    42 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = null;
    43 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "null" is not a valid currency code..
    44 
    45 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = undefined;
    46 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: Member ApplePayRequest.currencyCode is required and must be an instance of DOMString.
    47 
    48 SETUP: paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = 7;
    49 PASS request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show() rejected promise  with TypeError: "7" is not a valid currency code..
    50 
    5131Testing ApplePayRequest.supportedNetworks
    5232
     
    219199PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
    220200
     201SETUP: paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }];
     202PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
    221203Testing PaymentDetails.shippingOptions
    222204
     
    254236PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() threw exception TypeError: Type error.
    255237
     238SETUP: paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }];
     239PASS request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show() rejected promise  with TypeError: "EUR" does not match the expected currency of "USD". Apple Pay requires all PaymentCurrencyAmounts to use the same currency code..
    256240Testing PaymentOptions
    257241
  • trunk/LayoutTests/http/tests/ssl/applepay/PaymentRequest.https.html

    r223160 r223163  
    1919            merchantIdentifier: '',
    2020            countryCode: 'US',
    21             currencyCode: 'USD',
    2221            supportedNetworks: ['visa', 'masterCard'],
    2322            merchantCapabilities: ['supports3DS'],
     
    7271    debug("")
    7372    await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.countryCode = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    74     debug("")
    75 
    76     debug("Testing ApplePayRequest.currencyCode")
    77     debug("")
    78     await logAndShouldReject("paymentMethod = validPaymentMethod(); delete paymentMethod.data.currencyCode;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    79     debug("")
    80     await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = 'invalid';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    81     debug("")
    82     await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = '';", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    83     debug("")
    84     await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = null;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    85     debug("")
    86     await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = undefined;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    87     debug("")
    88     await logAndShouldReject("paymentMethod = validPaymentMethod(); paymentMethod.data.currencyCode = 7;", "request = new PaymentRequest([paymentMethod], validPaymentDetails()); request.show()")
    8973    debug("")
    9074
     
    191175    logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
    192176    logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: '10.00', type: 'invalid' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
    193    
     177    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.displayItems = [{ label: 'label', amount: { currency: 'EUR', value: '10.00' } }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
     178
    194179    debug("Testing PaymentDetails.shippingOptions")
    195180    debug("");
     
    205190    logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '', detail: '', identifier: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
    206191    logAndShouldThrow("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: '-1', detail: '', identifier: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
     192    await logAndShouldReject("paymentDetails = validPaymentDetails(); paymentDetails.shippingOptions = [{ amount: { currency: 'EUR', value: '10.00' }, id: '', label: '' }];", "request = new PaymentRequest([validPaymentMethod()], paymentDetails); request.show()")
    207193
    208194    debug("Testing PaymentOptions")
  • trunk/Source/WebCore/ChangeLog

    r223160 r223163  
     12017-10-10  Andy Estes  <aestes@apple.com>
     2
     3        [Payment Request] Validate that all PaymentCurrencyAmounts use the same currency code when using Apple Pay
     4        https://bugs.webkit.org/show_bug.cgi?id=178150
     5
     6        Reviewed by Tim Horton.
     7
     8        Apple Pay requires a single currency code, but the Payment Request API allows the client to
     9        specify a currency code for each PaymentCurrencyAmount.
     10
     11        Instead of having a required currencyCode property on ApplePayRequest and ignoring the
     12        currency property on PaymentCurrencyAmount, validate that all PaymentCurrencyAmounts use the
     13        same currency code and use that as ApplePaySessionPaymentRequest's currencyCode.
     14
     15        Added test cases to http/tests/ssl/applepay/PaymentRequest.https.html.
     16
     17        * Modules/applepay/ApplePayPaymentRequest.h:
     18        * Modules/applepay/ApplePayPaymentRequest.idl:
     19        * Modules/applepay/ApplePayRequestBase.cpp:
     20        (WebCore::convertAndValidate):
     21        * Modules/applepay/ApplePayRequestBase.h:
     22        * Modules/applepay/ApplePayRequestBase.idl:
     23        * Modules/applepay/ApplePaySession.cpp:
     24        (WebCore::convertAndValidate):
     25        * Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
     26        (WebCore::validate):
     27        (WebCore::convertAndValidate):
     28        (WebCore::ApplePayPaymentHandler::show):
     29        * Modules/applepay/paymentrequest/ApplePayRequest.idl:
     30
    1312017-10-10  Andy Estes  <aestes@apple.com>
    232
  • trunk/Source/WebCore/Modules/applepay/ApplePayPaymentRequest.h

    r222921 r223163  
    3030#include "ApplePayLineItem.h"
    3131#include "ApplePayPaymentContact.h"
    32 #include "ApplePayRequest.h"
     32#include "ApplePayRequestBase.h"
    3333#include "ApplePaySessionPaymentRequest.h"
    3434#include "ApplePayShippingMethod.h"
     
    3636namespace WebCore {
    3737
    38 struct ApplePayPaymentRequest : ApplePayRequest {
     38struct ApplePayPaymentRequest : ApplePayRequestBase {
    3939    using ShippingType = ApplePaySessionPaymentRequest::ShippingType;
     40
     41    String currencyCode;
    4042
    4143    std::optional<Vector<ApplePayContactField>> requiredShippingContactFields;
  • trunk/Source/WebCore/Modules/applepay/ApplePayPaymentRequest.idl

    r222921 r223163  
    3939    sequence<ApplePayLineItem> lineItems;
    4040
     41    required DOMString currencyCode;
     42
    4143    sequence<ApplePayContactField> requiredShippingContactFields;
    4244    ApplePayPaymentContact shippingContact;
  • trunk/Source/WebCore/Modules/applepay/ApplePayRequestBase.cpp

    r222921 r223163  
    4747{
    4848    ApplePaySessionPaymentRequest result;
    49 
    5049    result.setCountryCode(request.countryCode);
    51     result.setCurrencyCode(request.currencyCode);
    5250
    5351    auto merchantCapabilities = convertAndValidate(request.merchantCapabilities);
  • trunk/Source/WebCore/Modules/applepay/ApplePayRequestBase.h

    r222921 r223163  
    3838    Vector<String> supportedNetworks;
    3939    String countryCode;
    40     String currencyCode;
    4140
    4241    std::optional<Vector<ApplePayContactField>> requiredBillingContactFields;
  • trunk/Source/WebCore/Modules/applepay/ApplePayRequestBase.idl

    r222921 r223163  
    3030    required sequence<DOMString> supportedNetworks; // FIXME: Should this be an sequence of enums?
    3131    required DOMString countryCode;
    32     required DOMString currencyCode;
    3332
    3433    sequence<ApplePayContactField> requiredBillingContactFields;
  • trunk/Source/WebCore/Modules/applepay/ApplePaySession.cpp

    r222921 r223163  
    214214
    215215    auto result = convertedRequest.releaseReturnValue();
     216    result.setCurrencyCode(paymentRequest.currencyCode);
    216217
    217218    auto total = convertAndValidateTotal(WTFMove(paymentRequest.total));
  • trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp

    r223160 r223163  
    6868}
    6969
    70 static ApplePaySessionPaymentRequest::LineItem convert(const PaymentItem& item)
    71 {
     70static ExceptionOr<void> validate(const PaymentCurrencyAmount& amount, const String& expectedCurrency)
     71{
     72    if (amount.currency != expectedCurrency)
     73        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.") };
     74    return { };
     75}
     76
     77static ExceptionOr<ApplePaySessionPaymentRequest::LineItem> convertAndValidate(const PaymentItem& item, const String& expectedCurrency)
     78{
     79    auto exception = validate(item.amount, expectedCurrency);
     80    if (exception.hasException())
     81        return exception.releaseException();
     82
    7283    ApplePaySessionPaymentRequest::LineItem lineItem;
    7384    lineItem.amount = item.amount.value;
     
    7788}
    7889
    79 static Vector<ApplePaySessionPaymentRequest::LineItem> convert(const Vector<PaymentItem>& lineItems)
     90static ExceptionOr<Vector<ApplePaySessionPaymentRequest::LineItem>> convertAndValidate(const Vector<PaymentItem>& lineItems, const String& expectedCurrency)
    8091{
    8192    Vector<ApplePaySessionPaymentRequest::LineItem> result;
    8293    result.reserveInitialCapacity(lineItems.size());
    83     for (auto& lineItem : lineItems)
    84         result.uncheckedAppend(convert(lineItem));
     94    for (auto& lineItem : lineItems) {
     95        auto convertedLineItem = convertAndValidate(lineItem, expectedCurrency);
     96        if (convertedLineItem.hasException())
     97            return convertedLineItem.releaseException();
     98        result.uncheckedAppend(convertedLineItem.releaseReturnValue());
     99    }
    85100    return result;
    86101}
     
    111126}
    112127
    113 static ApplePaySessionPaymentRequest::ShippingMethod convert(const PaymentShippingOption& shippingOption)
    114 {
     128static ExceptionOr<ApplePaySessionPaymentRequest::ShippingMethod> convertAndValidate(const PaymentShippingOption& shippingOption, const String& expectedCurrency)
     129{
     130    auto exception = validate(shippingOption.amount, expectedCurrency);
     131    if (exception.hasException())
     132        return exception.releaseException();
     133
    115134    ApplePaySessionPaymentRequest::ShippingMethod result;
    116135    result.amount = shippingOption.amount.value;
     
    138157
    139158    ApplePaySessionPaymentRequest request = validatedRequest.releaseReturnValue();
    140     request.setTotal(convert(m_paymentRequest->paymentDetails().total));
    141 
    142     auto lineItems = convert(m_paymentRequest->paymentDetails().displayItems);
     159
     160    String expectedCurrency = m_paymentRequest->paymentDetails().total.amount.currency;
     161    request.setCurrencyCode(expectedCurrency);
     162
     163    auto total = convertAndValidate(m_paymentRequest->paymentDetails().total, expectedCurrency);
     164    ASSERT(!total.hasException());
     165    request.setTotal(total.releaseReturnValue());
     166
     167    auto convertedLineItems = convertAndValidate(m_paymentRequest->paymentDetails().displayItems, expectedCurrency);
     168    if (convertedLineItems.hasException())
     169        return convertedLineItems.releaseException();
     170
     171    auto lineItems = convertedLineItems.releaseReturnValue();
    143172    for (auto& modifier : m_paymentRequest->paymentDetails().modifiers) {
    144173        auto convertedIdentifier = convertAndValidatePaymentMethodIdentifier(modifier.supportedMethods);
    145         if (convertedIdentifier && handlesIdentifier(*convertedIdentifier))
    146             lineItems.appendVector(convert(modifier.additionalDisplayItems));
     174        if (!convertedIdentifier || !handlesIdentifier(*convertedIdentifier))
     175            continue;
     176
     177        auto additionalDisplayItems = convertAndValidate(modifier.additionalDisplayItems, expectedCurrency);
     178        if (additionalDisplayItems.hasException())
     179            return additionalDisplayItems.releaseException();
     180
     181        lineItems.appendVector(additionalDisplayItems.releaseReturnValue());
    147182    }
    148183    request.setLineItems(lineItems);
     
    154189    Vector<ApplePaySessionPaymentRequest::ShippingMethod> shippingMethods;
    155190    shippingMethods.reserveInitialCapacity(m_paymentRequest->paymentDetails().shippingOptions.size());
    156     for (auto& shippingOption : m_paymentRequest->paymentDetails().shippingOptions)
    157         shippingMethods.uncheckedAppend(convert(shippingOption));
     191    for (auto& shippingOption : m_paymentRequest->paymentDetails().shippingOptions) {
     192        auto convertedShippingOption = convertAndValidate(shippingOption, expectedCurrency);
     193        if (convertedShippingOption.hasException())
     194            return convertedShippingOption.releaseException();
     195        shippingMethods.uncheckedAppend(convertedShippingOption.releaseReturnValue());
     196    }
    158197    request.setShippingMethods(shippingMethods);
    159198
  • trunk/Source/WebCore/Modules/applepay/paymentrequest/ApplePayRequest.idl

    r223160 r223163  
    3030    required DOMString merchantIdentifier;
    3131};
     32
Note: See TracChangeset for help on using the changeset viewer.