Commit 95984a3b authored by gogerald's avatar gogerald Committed by Commit Bot

[Payments] Filtering service worker payment apps based on capabilities

This CL parses and stores 'basic-card' specific capabilities, and uses
them to filter service worker payment apps.

The capabilities will also be used to filter modifiers.

Bug: 777470
Change-Id: Ifab1054ec3bccd4f279cde5348cc68abf504a88d
Reviewed-on: https://chromium-review.googlesource.com/730845
Commit-Queue: Ganggui Tang <gogerald@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#512994}
parent dd23f06c
......@@ -16,6 +16,7 @@ import org.chromium.payments.mojom.PaymentMethodData;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
......@@ -33,14 +34,60 @@ import javax.annotation.Nullable;
* @see https://w3c.github.io/webpayments-payment-handler/
*/
public class ServiceWorkerPaymentApp extends PaymentInstrument implements PaymentApp {
private final static String BASIC_CARD_PAYMENT_METHOD = "basic-card";
private final WebContents mWebContents;
private final long mRegistrationId;
private final Drawable mIcon;
private final Set<String> mMethodNames;
private final Capabilities[] mCapabilities;
private final boolean mCanPreselect;
private final Set<String> mPreferredRelatedApplicationIds;
private final boolean mIsIncognito;
/**
* This class represents capabilities of a payment instrument. It is currently only used for
* 'basic-card' payment instrument.
*/
protected static class Capabilities {
// Stores mojom::BasicCardNetwork.
private int[] mSupportedCardNetworks;
// Stores mojom::BasicCardType.
private int[] mSupportedCardTypes;
/**
* Build capabilities for a payment instrument.
*
* @param supportedCardNetworks The supported card networks of a 'basic-card' payment
* instrument.
* @param supportedCardTypes The supported card types of a 'basic-card' payment
* instrument.
*/
/* package */ Capabilities(int[] supportedCardNetworks, int[] supportedCardTypes) {
mSupportedCardNetworks = supportedCardNetworks;
mSupportedCardTypes = supportedCardTypes;
}
/**
* Gets supported card networks.
*
* @return a set of mojom::BasicCardNetwork.
*/
/* package */ int[] getSupportedCardNetworks() {
return mSupportedCardNetworks;
}
/**
* Gets supported card types.
*
* @return a set of mojom::BasicCardType.
*/
/* package */ int[] getSupportedCardTypes() {
return mSupportedCardTypes;
}
}
/**
* Build a service worker payment app instance per origin.
*
......@@ -57,11 +104,14 @@ public class ServiceWorkerPaymentApp extends PaymentInstrument implements Paymen
* @param icon The drawable icon of the payment app.
* @param methodNames A set of payment method names supported by the payment
* app.
* @param capabilities A set of capabilities of the payment instruments in
* this payment app (only valid for basic-card payment
* method for now).
* @param preferredRelatedApplicationIds A set of preferred related application Ids.
*/
public ServiceWorkerPaymentApp(WebContents webContents, long registrationId, URI scope,
String label, @Nullable String sublabel, @Nullable String tertiarylabel,
@Nullable Drawable icon, String[] methodNames,
@Nullable Drawable icon, String[] methodNames, Capabilities[] capabilities,
String[] preferredRelatedApplicationIds) {
super(scope.toString(), label, sublabel, tertiarylabel, icon);
mWebContents = webContents;
......@@ -77,6 +127,8 @@ public class ServiceWorkerPaymentApp extends PaymentInstrument implements Paymen
mMethodNames.add(methodNames[i]);
}
mCapabilities = Arrays.copyOf(capabilities, capabilities.length);
mPreferredRelatedApplicationIds = new HashSet<>();
Collections.addAll(mPreferredRelatedApplicationIds, preferredRelatedApplicationIds);
......@@ -89,6 +141,17 @@ public class ServiceWorkerPaymentApp extends PaymentInstrument implements Paymen
public void getInstruments(Map<String, PaymentMethodData> methodDataMap, String origin,
String iframeOrigin, byte[][] unusedCertificateChain,
Map<String, PaymentDetailsModifier> modifiers, final InstrumentsCallback callback) {
if (isOnlySupportBasiccard(methodDataMap)
&& !matchBasiccardCapabilities(methodDataMap.get(BASIC_CARD_PAYMENT_METHOD))) {
// Do not list this app if 'basic-card' is the only supported payment method with
// unmatched capabilities.
new Handler().post(() -> {
List<PaymentInstrument> instruments = new ArrayList();
callback.onInstrumentsReady(ServiceWorkerPaymentApp.this, instruments);
});
return;
}
if (mIsIncognito) {
new Handler().post(() -> {
List<PaymentInstrument> instruments = new ArrayList();
......@@ -109,6 +172,72 @@ public class ServiceWorkerPaymentApp extends PaymentInstrument implements Paymen
});
}
// Returns true if 'basic-card' is the only supported payment method of this payment app in the
// payment request.
private boolean isOnlySupportBasiccard(Map<String, PaymentMethodData> methodDataMap) {
Set<String> requestMethods = new HashSet<>(methodDataMap.keySet());
requestMethods.retainAll(mMethodNames);
return requestMethods.size() == 1 && requestMethods.contains(BASIC_CARD_PAYMENT_METHOD);
}
// Matches |requestMethodData|.supportedTypes and |requestMethodData|.supportedNetwokrs for
// 'basic-card' payment method with the Capabilities in this payment app to determine whether
// this payment app supports |requestMethodData|.
private boolean matchBasiccardCapabilities(PaymentMethodData requestMethodData) {
// Empty supported card types and networks in payment request method data indicates it
// supports all card types and networks.
if (requestMethodData.supportedTypes.length == 0
&& requestMethodData.supportedNetworks.length == 0) {
return true;
}
// Payment app with emtpy capabilities can only match payment request method data with empty
// supported card types and networks.
if (mCapabilities.length == 0) return false;
Set<Integer> requestSupportedTypes = new HashSet<>();
for (int i = 0; i < requestMethodData.supportedTypes.length; i++) {
requestSupportedTypes.add(requestMethodData.supportedTypes[i]);
}
Set<Integer> requestSupportedNetworks = new HashSet<>();
for (int i = 0; i < requestMethodData.supportedNetworks.length; i++) {
requestSupportedNetworks.add(requestMethodData.supportedNetworks[i]);
}
// If requestSupportedTypes and requestSupportedNetworks are not empty, match them with the
// capabilities. Break out of the for loop if a matched capability has been found. So 'j
// < mCapabilities.length' indicates that there is a matched capability in this payment
// app.
int j = 0;
for (; j < mCapabilities.length; j++) {
if (!requestSupportedTypes.isEmpty()) {
int[] supportedTypes = mCapabilities[j].getSupportedCardTypes();
Set<Integer> capabilitiesSupportedCardTypes = new HashSet<>();
for (int i = 0; i < supportedTypes.length; i++) {
capabilitiesSupportedCardTypes.add(supportedTypes[i]);
}
capabilitiesSupportedCardTypes.retainAll(requestSupportedTypes);
if (capabilitiesSupportedCardTypes.isEmpty()) continue;
}
if (!requestSupportedNetworks.isEmpty()) {
int[] supportedNetworks = mCapabilities[j].getSupportedCardNetworks();
Set<Integer> capabilitiesSupportedCardNetworks = new HashSet<>();
for (int i = 0; i < supportedNetworks.length; i++) {
capabilitiesSupportedCardNetworks.add(supportedNetworks[i]);
}
capabilitiesSupportedCardNetworks.retainAll(requestSupportedNetworks);
if (capabilitiesSupportedCardNetworks.isEmpty()) continue;
}
break;
}
return j < mCapabilities.length;
}
@Override
public Set<String> getAppMethodNames() {
return Collections.unmodifiableSet(mMethodNames);
......
......@@ -165,10 +165,23 @@ public class ServiceWorkerPaymentAppBridge implements PaymentAppFactory.PaymentA
return item.amount.currencySystem;
}
@CalledByNative
private static Object[] createCapabilities(int count) {
return new ServiceWorkerPaymentApp.Capabilities[count];
}
@CalledByNative
private static void addCapabilities(Object[] capabilities, int index,
int[] supportedCardNetworks, int[] supportedCardTypes) {
assert index < capabilities.length;
capabilities[index] =
new ServiceWorkerPaymentApp.Capabilities(supportedCardNetworks, supportedCardTypes);
}
@CalledByNative
private static void onPaymentAppCreated(long registrationId, String scope, String label,
@Nullable String sublabel, @Nullable String tertiarylabel, @Nullable Bitmap icon,
String[] methodNameArray, String[] preferredRelatedApplications,
String[] methodNameArray, Object[] capabilities, String[] preferredRelatedApplications,
WebContents webContents, Object callback) {
Context context = ChromeActivity.fromWebContents(webContents);
if (context == null) return;
......@@ -181,7 +194,8 @@ public class ServiceWorkerPaymentAppBridge implements PaymentAppFactory.PaymentA
.onPaymentAppCreated(new ServiceWorkerPaymentApp(webContents, registrationId,
scopeUri, label, sublabel, tertiarylabel,
icon == null ? null : new BitmapDrawable(context.getResources(), icon),
methodNameArray, preferredRelatedApplications));
methodNameArray, (ServiceWorkerPaymentApp.Capabilities[]) capabilities,
preferredRelatedApplications));
}
@CalledByNative
......
......@@ -37,6 +37,7 @@ using ::base::android::JavaRef;
using ::base::android::ScopedJavaGlobalRef;
using ::base::android::ScopedJavaLocalRef;
using ::base::android::ToJavaArrayOfStrings;
using ::base::android::ToJavaIntArray;
using ::payments::mojom::CanMakePaymentEventData;
using ::payments::mojom::CanMakePaymentEventDataPtr;
using ::payments::mojom::PaymentCurrencyAmount;
......@@ -105,6 +106,18 @@ void OnGotAllPaymentApps(const JavaRef<jobject>& jweb_contents,
}
}
base::android::ScopedJavaLocalRef<jobjectArray> jcapabilities =
Java_ServiceWorkerPaymentAppBridge_createCapabilities(
env, app_info.second->capabilities.size());
for (size_t i = 0; i < app_info.second->capabilities.size(); i++) {
Java_ServiceWorkerPaymentAppBridge_addCapabilities(
env, jcapabilities, base::checked_cast<int>(i),
ToJavaIntArray(
env, app_info.second->capabilities[i].supported_card_networks),
ToJavaIntArray(
env, app_info.second->capabilities[i].supported_card_types));
}
Java_ServiceWorkerPaymentAppBridge_onPaymentAppCreated(
env, app_info.second->registration_id,
ConvertUTF8ToJavaString(env, app_info.second->scope.spec()),
......@@ -122,6 +135,7 @@ void OnGotAllPaymentApps(const JavaRef<jobject>& jweb_contents,
? nullptr
: gfx::ConvertToJavaBitmap(app_info.second->icon.get()),
ToJavaArrayOfStrings(env, app_info.second->enabled_methods),
jcapabilities,
ToJavaArrayOfStrings(env, preferred_related_application_ids),
jweb_contents, jcallback);
}
......
......@@ -156,6 +156,7 @@ if (is_ios) {
"//components/test/data/payments/blob_url.js",
"//components/test/data/payments/bobpay.js",
"//components/test/data/payments/bobpay_and_basic_card_with_modifiers.js",
"//components/test/data/payments/bobpay_and_basic_card_with_optional_data.js",
"//components/test/data/payments/bobpay_and_cards.js",
"//components/test/data/payments/bobpay_ui_skip.js",
"//components/test/data/payments/bobpay_ui_skip_preload.js",
......@@ -189,6 +190,7 @@ if (is_ios) {
"//components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html",
"//components/test/data/payments/payment_request_blob_url_test.html",
"//components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html",
"//components/test/data/payments/payment_request_bobpay_and_basic_card_with_optional_data_test.html",
"//components/test/data/payments/payment_request_bobpay_and_cards_test.html",
"//components/test/data/payments/payment_request_bobpay_test.html",
"//components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html",
......
......@@ -72,13 +72,13 @@ function buyWithBobPayDiscount() { // eslint-disable-line no-unused-vars
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print(error.message);
});
})
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print(error.message);
});
})
.catch(function(error) {
print(error.message);
});
......@@ -137,40 +137,40 @@ function creditSupportedType() { // eslint-disable-line no-unused-vars
function debitSupportedType() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
modifiers: [{
supportedMethods: ['basic-card'],
total: {
label: 'Total',
amount: {currency: 'USD', value: '4.00'},
},
additionalDisplayItems: [{
label: 'basic-card discount',
amount: {currency: 'USD', value: '-1.00'},
}],
data: {
discountProgramParticipantId: '86328764873265',
supportedTypes: ['debit'],
},
[{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
modifiers: [{
supportedMethods: ['basic-card'],
total: {
label: 'Total',
amount: {currency: 'USD', value: '4.00'},
},
additionalDisplayItems: [{
label: 'basic-card discount',
amount: {currency: 'USD', value: '-1.00'},
}],
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print(error.message);
});
data: {
discountProgramParticipantId: '86328764873265',
supportedTypes: ['debit'],
},
}],
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print(error.message);
});
} catch (error) {
print(error.message);
}
})
.catch(function(error) {
print(error.message);
});
} catch (error) {
print(error.message);
}
}
/**
......
/*
* Copyright 2017 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**
* Launches the PaymentRequest UI with Bob Pay as payment method.
*/
function buy() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{supportedMethods: ['https://bobpay.com']}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with all cards as payment methods.
*/
function buyWithAllCards() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{supportedMethods: ['basic-card']}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with visa credit card as payment method.
*/
function buyWithVisaCredit() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{
supportedMethods: ['basic-card'],
data: {
supportedTypes: ['credit'],
supportedNetworks: ['visa'],
},
}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with visa debit card as payment method.
*/
function buyWithVisaDebit() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{
supportedMethods: ['basic-card'],
data: {
supportedTypes: ['debit'],
supportedNetworks: ['visa'],
},
}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with credit card as payment method.
*/
function buyWithCredit() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{
supportedMethods: ['basic-card'],
data: {
supportedTypes: ['credit'],
},
}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with visa card as payment method.
*/
function buyWithVisa() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{
supportedMethods: ['basic-card'],
data: {
supportedNetworks: ['visa'],
},
}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
/**
* Launches the PaymentRequest UI with Bob Pay and visa card as payment methods.
*/
function buyWithBobPayAndVisa() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{
supportedMethods: ['https://bobpay.com', 'basic-card'],
data: {
supportedNetworks: ['visa'],
},
}],
{
total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(JSON.stringify(resp, undefined, 2));
})
.catch(function(error) {
print('complete() rejected<br>' + error.message);
});
})
.catch(function(error) {
print('show() rejected<br>' + error.message);
});
} catch (error) {
print('exception thrown<br>' + error.message);
}
}
<!DOCTYPE html>
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<head>
<title>Bob Pay and basic-card with optional data test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<button onclick="buy()" id="buy">Bob Pay Test</button>
<button onclick="buyWithAllCards()" id="buy_with_all_cards">All cards test</button>
<button onclick="buyWithVisaCredit()" id="buy_with_visa_credit">Visa credit card test</button>
<button onclick="buyWithVisaDebit()" id="buy_with_visa_debit">Visa debit card test</button>
<button onclick="buyWithCredit()" id="buy_with_credit">Credit card test</button>
<button onclick="buyWithVisa()" id="buy_with_visa">Visa card test</button>
<button onclick="buyWithBobPayAndVisa()" id="buy_with_bobpay_and_visa">Bob Pay And Visa card test</button>
<pre id="result"></pre>
<script src="util.js"></script>
<script src="bobpay_and_basic_card_with_optional_data.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -32,6 +32,8 @@ message StoredPaymentInstrumentProto {
optional string stringified_capabilities = 5;
repeated StoredPaymentInstrumentImageObject icons = 6;
optional string decoded_instrument_icon = 7;
repeated int32 supported_card_networks = 8;
repeated int32 supported_card_types = 9;
}
message StoredRelatedApplicationProto {
......
......@@ -460,6 +460,15 @@ void PaymentAppDatabase::DidReadAllPaymentInstruments(
for (const auto& method : instrument_proto.enabled_methods()) {
apps[id]->enabled_methods.push_back(method);
}
apps[id]->capabilities.emplace_back(StoredCapabilities());
for (const auto& network : instrument_proto.supported_card_networks()) {
apps[id]->capabilities.back().supported_card_networks.emplace_back(
network);
}
for (const auto& type : instrument_proto.supported_card_types()) {
apps[id]->capabilities.back().supported_card_types.emplace_back(type);
}
}
std::move(callback).Run(std::move(apps));
......@@ -655,6 +664,12 @@ void PaymentAppDatabase::DidFindRegistrationToWritePaymentInstrument(
}
instrument_proto.set_stringified_capabilities(
instrument->stringified_capabilities);
for (const auto& network : instrument->supported_networks) {
instrument_proto.add_supported_card_networks(static_cast<int32_t>(network));
}
for (const auto& type : instrument->supported_types) {
instrument_proto.add_supported_card_types(static_cast<int32_t>(type));
}
std::string serialized_instrument;
bool success = instrument_proto.SerializeToString(&serialized_instrument);
......
......@@ -10,6 +10,12 @@ StoredRelatedApplication::StoredRelatedApplication() = default;
StoredRelatedApplication::~StoredRelatedApplication() = default;
StoredCapabilities::StoredCapabilities() = default;
StoredCapabilities::StoredCapabilities(const StoredCapabilities&) = default;
StoredCapabilities::~StoredCapabilities() = default;
StoredPaymentApp::StoredPaymentApp() = default;
StoredPaymentApp::~StoredPaymentApp() = default;
......
......@@ -24,6 +24,19 @@ struct CONTENT_EXPORT StoredRelatedApplication {
std::string id;
};
// This class represents the stored capabilities.
struct CONTENT_EXPORT StoredCapabilities {
StoredCapabilities();
StoredCapabilities(const StoredCapabilities&);
~StoredCapabilities();
// A list of ::payments::mojom::BasicCardNetwork.
std::vector<int32_t> supported_card_networks;
// A list of ::payments::mojom::BasicCardType.
std::vector<int32_t> supported_card_types;
};
// This class represents the stored payment app.
struct CONTENT_EXPORT StoredPaymentApp {
StoredPaymentApp();
......@@ -44,6 +57,12 @@ struct CONTENT_EXPORT StoredPaymentApp {
// A list of one or more enabled payment methods in this payment app.
std::vector<std::string> enabled_methods;
// A list of capabilities in this payment app.
// |capabilities| is non-empty only if |enabled_methods| contains "basic-card"
// for now and these |capabilities| apply only to the "basic-card" instrument,
// although we don't store the instruments individually.
std::vector<StoredCapabilities> capabilities;
// A flag indicates whether the app prefers the related applications.
bool prefer_related_applications = false;
......
......@@ -10,6 +10,8 @@ blink_modules_sources("payments") {
"AbortPaymentEvent.h",
"AbortPaymentRespondWithObserver.cpp",
"AbortPaymentRespondWithObserver.h",
"BasicCardHelper.cpp",
"BasicCardHelper.h",
"CanMakePaymentEvent.cpp",
"CanMakePaymentEvent.h",
"CanMakePaymentRespondWithObserver.cpp",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/payments/BasicCardHelper.h"
#include "bindings/modules/v8/V8BasicCardRequest.h"
#include "modules/payments/BasicCardRequest.h"
namespace blink {
namespace {
using ::payments::mojom::blink::BasicCardNetwork;
using ::payments::mojom::blink::BasicCardType;
static const size_t kMaxListSize = 1024;
const struct {
const payments::mojom::BasicCardNetwork code;
const char* const name;
} kBasicCardNetworks[] = {{BasicCardNetwork::AMEX, "amex"},
{BasicCardNetwork::DINERS, "diners"},
{BasicCardNetwork::DISCOVER, "discover"},
{BasicCardNetwork::JCB, "jcb"},
{BasicCardNetwork::MASTERCARD, "mastercard"},
{BasicCardNetwork::MIR, "mir"},
{BasicCardNetwork::UNIONPAY, "unionpay"},
{BasicCardNetwork::VISA, "visa"}};
const struct {
const BasicCardType code;
const char* const name;
} kBasicCardTypes[] = {{BasicCardType::CREDIT, "credit"},
{BasicCardType::DEBIT, "debit"},
{BasicCardType::PREPAID, "prepaid"}};
} // namespace
void BasicCardHelper::parseBasiccardData(
const ScriptValue& input,
Vector<BasicCardNetwork>& supported_networks_output,
Vector<BasicCardType>& supported_types_output,
ExceptionState& exception_state) {
DCHECK(!input.IsEmpty());
BasicCardRequest basic_card;
V8BasicCardRequest::ToImpl(input.GetIsolate(), input.V8Value(), basic_card,
exception_state);
if (exception_state.HadException())
return;
if (basic_card.hasSupportedNetworks()) {
if (basic_card.supportedNetworks().size() > kMaxListSize) {
exception_state.ThrowTypeError(
"basic-card supportedNetworks cannot be longer than 1024 elements");
return;
}
for (const String& network : basic_card.supportedNetworks()) {
for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
if (network == kBasicCardNetworks[i].name) {
supported_networks_output.push_back(kBasicCardNetworks[i].code);
break;
}
}
}
}
if (basic_card.hasSupportedTypes()) {
if (basic_card.supportedTypes().size() > kMaxListSize) {
exception_state.ThrowTypeError(
"basic-card supportedTypes cannot be longer than 1024 elements");
return;
}
for (const String& type : basic_card.supportedTypes()) {
for (size_t i = 0; i < arraysize(kBasicCardTypes); ++i) {
if (type == kBasicCardTypes[i].name) {
supported_types_output.push_back(kBasicCardTypes[i].code);
break;
}
}
}
}
}
bool BasicCardHelper::containsNetworkNames(const Vector<String>& input) {
for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
if (input.Contains(kBasicCardNetworks[i].name)) {
return true;
}
}
return false;
}
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BasicCardHelper_h
#define BasicCardHelper_h
#include "bindings/core/v8/ExceptionState.h"
#include "platform/wtf/Vector.h"
#include "public/platform/modules/payments/payment_request.mojom-blink.h"
namespace blink {
class BasicCardHelper {
STATIC_ONLY(BasicCardHelper);
public:
// Parse 'basic-card' data in |input| and store result in
// |supported_networks_output| and |supported_types_output| or throw
// exception.
static void parseBasiccardData(
const ScriptValue& input,
Vector<::payments::mojom::blink::BasicCardNetwork>&
supported_networks_output,
Vector<::payments::mojom::blink::BasicCardType>& supported_types_output,
ExceptionState&);
// Check whether |input| contains 'basic-card' network names.
static bool containsNetworkNames(const Vector<String>& input);
};
} // namespace blink
#endif // BasicCardHelper_h
......@@ -12,6 +12,7 @@
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/dom/DOMException.h"
#include "core/inspector/ConsoleMessage.h"
#include "modules/payments/BasicCardHelper.h"
#include "modules/payments/PaymentInstrument.h"
#include "modules/payments/PaymentManager.h"
#include "platform/wtf/Vector.h"
......@@ -200,6 +201,11 @@ ScriptPromise PaymentInstruments::set(ScriptState* script_state,
return exception_state.Reject(script_state);
}
instrument->stringified_capabilities = ToCoreString(value);
if (instrument->enabled_methods.Contains("basic-card")) {
BasicCardHelper::parseBasiccardData(
details.capabilities(), instrument->supported_networks,
instrument->supported_types, exception_state);
}
} else {
instrument->stringified_capabilities = WTF::g_empty_string;
}
......
......@@ -29,6 +29,7 @@
#include "modules/event_target_modules_names.h"
#include "modules/payments/AndroidPayMethodData.h"
#include "modules/payments/AndroidPayTokenization.h"
#include "modules/payments/BasicCardHelper.h"
#include "modules/payments/BasicCardRequest.h"
#include "modules/payments/HTMLIFrameElementPayments.h"
#include "modules/payments/PaymentAddress.h"
......@@ -134,20 +135,6 @@ struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> {
namespace blink {
namespace {
using ::payments::mojom::blink::BasicCardNetwork;
const struct {
const BasicCardNetwork code;
const char* const name;
} kBasicCardNetworks[] = {{BasicCardNetwork::AMEX, "amex"},
{BasicCardNetwork::DINERS, "diners"},
{BasicCardNetwork::DISCOVER, "discover"},
{BasicCardNetwork::JCB, "jcb"},
{BasicCardNetwork::MASTERCARD, "mastercard"},
{BasicCardNetwork::MIR, "mir"},
{BasicCardNetwork::UNIONPAY, "unionpay"},
{BasicCardNetwork::VISA, "visa"}};
// If the website does not call complete() 60 seconds after show() has been
// resolved, then behave as if the website called complete("fail").
static const int kCompleteTimeoutSeconds = 60;
......@@ -435,54 +422,8 @@ void SetAndroidPayMethodData(const ScriptValue& input,
void SetBasicCardMethodData(const ScriptValue& input,
PaymentMethodDataPtr& output,
ExceptionState& exception_state) {
BasicCardRequest basic_card;
V8BasicCardRequest::ToImpl(input.GetIsolate(), input.V8Value(), basic_card,
exception_state);
if (exception_state.HadException())
return;
if (basic_card.hasSupportedNetworks()) {
if (basic_card.supportedNetworks().size() > kMaxListSize) {
exception_state.ThrowTypeError(
"basic-card supportedNetworks cannot be longer than 1024 elements");
return;
}
for (const String& network : basic_card.supportedNetworks()) {
for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
if (network == kBasicCardNetworks[i].name) {
output->supported_networks.push_back(kBasicCardNetworks[i].code);
break;
}
}
}
}
if (basic_card.hasSupportedTypes()) {
using ::payments::mojom::blink::BasicCardType;
if (basic_card.supportedTypes().size() > kMaxListSize) {
exception_state.ThrowTypeError(
"basic-card supportedTypes cannot be longer than 1024 elements");
return;
}
const struct {
const BasicCardType code;
const char* const name;
} kBasicCardTypes[] = {{BasicCardType::CREDIT, "credit"},
{BasicCardType::DEBIT, "debit"},
{BasicCardType::PREPAID, "prepaid"}};
for (const String& type : basic_card.supportedTypes()) {
for (size_t i = 0; i < arraysize(kBasicCardTypes); ++i) {
if (type == kBasicCardTypes[i].name) {
output->supported_types.push_back(kBasicCardTypes[i].code);
break;
}
}
}
}
BasicCardHelper::parseBasiccardData(input, output->supported_networks,
output->supported_types, exception_state);
}
void StringifyAndParseMethodSpecificData(
......@@ -530,13 +471,10 @@ void StringifyAndParseMethodSpecificData(
void CountPaymentRequestNetworkNameInSupportedMethods(
const Vector<String>& supported_methods,
ExecutionContext& execution_context) {
for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
if (supported_methods.Contains(kBasicCardNetworks[i].name)) {
Deprecation::CountDeprecation(
&execution_context,
WebFeature::kPaymentRequestNetworkNameInSupportedMethods);
break;
}
if (BasicCardHelper::containsNetworkNames(supported_methods)) {
Deprecation::CountDeprecation(
&execution_context,
WebFeature::kPaymentRequestNetworkNameInSupportedMethods);
}
}
......
......@@ -26,6 +26,11 @@ struct PaymentInstrument {
array<blink.mojom.ManifestIcon> icons;
array<string> enabled_methods;
string stringified_capabilities;
// Parsed basic-card specific capabilities.
// Below arrays are non-empty only if enabled_methods contains "basic-card".
array<BasicCardNetwork> supported_networks;
array<BasicCardType> supported_types;
};
// This interface provides implementation of PaymentInstruments.idl
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment