blob: 12a624b6e1b28342a3cf60c1e6f31d619b714b20 [file] [log] [blame]
// 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 "components/payments/core/payment_request_data_util.h"
#include <memory>
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/validation.h"
#include "components/payments/core/basic_card_response.h"
#include "components/payments/core/payment_method_data.h"
#include "components/payments/core/payments_validators.h"
#include "url/url_constants.h"
namespace payments {
namespace data_util {
mojom::PaymentAddressPtr GetPaymentAddressFromAutofillProfile(
const autofill::AutofillProfile& profile,
const std::string& app_locale) {
mojom::PaymentAddressPtr payment_address = mojom::PaymentAddress::New();
if (profile.IsEmpty(app_locale))
return payment_address;
payment_address->country =
base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
DCHECK(PaymentsValidators::IsValidCountryCodeFormat(payment_address->country,
nullptr));
payment_address->address_line =
base::SplitString(base::UTF16ToUTF8(profile.GetInfo(
autofill::ADDRESS_HOME_STREET_ADDRESS, app_locale)),
"\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
payment_address->region = base::UTF16ToUTF8(
profile.GetInfo(autofill::ADDRESS_HOME_STATE, app_locale));
payment_address->city = base::UTF16ToUTF8(
profile.GetInfo(autofill::ADDRESS_HOME_CITY, app_locale));
payment_address->dependent_locality = base::UTF16ToUTF8(
profile.GetInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, app_locale));
payment_address->postal_code = base::UTF16ToUTF8(
profile.GetInfo(autofill::ADDRESS_HOME_ZIP, app_locale));
payment_address->sorting_code = base::UTF16ToUTF8(
profile.GetInfo(autofill::ADDRESS_HOME_SORTING_CODE, app_locale));
payment_address->organization =
base::UTF16ToUTF8(profile.GetInfo(autofill::COMPANY_NAME, app_locale));
payment_address->recipient =
base::UTF16ToUTF8(profile.GetInfo(autofill::NAME_FULL, app_locale));
// The autofill profile |language_code| is the BCP-47 language tag (e.g.,
// "ja-Latn"), which can be split into a language code (e.g., "ja") and a
// script code (e.g., "Latn").
PaymentsValidators::SplitLanguageTag(profile.language_code(),
&payment_address->language_code,
&payment_address->script_code);
// TODO(crbug.com/705945): Format phone number according to spec.
payment_address->phone =
base::UTF16ToUTF8(profile.GetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER));
return payment_address;
}
std::unique_ptr<BasicCardResponse> GetBasicCardResponseFromAutofillCreditCard(
const autofill::CreditCard& card,
const base::string16& cvc,
const autofill::AutofillProfile& billing_profile,
const std::string& app_locale) {
std::unique_ptr<BasicCardResponse> response =
std::make_unique<BasicCardResponse>();
response->cardholder_name = card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL);
response->card_number = card.GetRawInfo(autofill::CREDIT_CARD_NUMBER);
response->expiry_month = card.GetRawInfo(autofill::CREDIT_CARD_EXP_MONTH);
response->expiry_year =
card.GetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
response->card_security_code = cvc;
response->billing_address =
GetPaymentAddressFromAutofillProfile(billing_profile, app_locale);
return response;
}
void ParseSupportedMethods(
const std::vector<PaymentMethodData>& method_data,
std::vector<std::string>* out_supported_networks,
std::set<std::string>* out_basic_card_specified_networks,
std::vector<GURL>* out_url_payment_method_identifiers,
std::set<std::string>* out_payment_method_identifiers) {
DCHECK(out_supported_networks->empty());
DCHECK(out_basic_card_specified_networks->empty());
DCHECK(out_url_payment_method_identifiers->empty());
DCHECK(out_payment_method_identifiers->empty());
const std::set<std::string> kBasicCardNetworks{
"amex", "diners", "discover", "jcb",
"mastercard", "mir", "unionpay", "visa"};
std::set<std::string> remaining_card_networks(kBasicCardNetworks);
std::set<GURL> url_payment_method_identifiers;
for (const PaymentMethodData& method_data_entry : method_data) {
if (method_data_entry.supported_method.empty())
return;
out_payment_method_identifiers->insert(method_data_entry.supported_method);
const char kBasicCardMethodName[] = "basic-card";
// If a card network is specified right in "supportedMethods", add it.
auto card_it =
remaining_card_networks.find(method_data_entry.supported_method);
if (card_it != remaining_card_networks.end()) {
out_supported_networks->push_back(method_data_entry.supported_method);
// |method| removed from |remaining_card_networks| so that it is not
// doubly added to |out_supported_networks|.
remaining_card_networks.erase(card_it);
} else if (method_data_entry.supported_method == kBasicCardMethodName) {
// For the "basic-card" method, check "supportedNetworks".
if (method_data_entry.supported_networks.empty()) {
// Empty |supported_networks| means all networks are supported.
out_supported_networks->insert(out_supported_networks->end(),
remaining_card_networks.begin(),
remaining_card_networks.end());
out_basic_card_specified_networks->insert(kBasicCardNetworks.begin(),
kBasicCardNetworks.end());
// Clear the set so that no further networks are added to
// |out_supported_networks|.
remaining_card_networks.clear();
} else {
// The merchant has specified a few basic card supported networks. Use
// the mapping to transform to known basic-card types.
for (const std::string& supported_network :
method_data_entry.supported_networks) {
// Make sure that the network was not already added to
// |out_supported_networks|. If it's still in
// |remaining_card_networks| it's fair game.
auto it = remaining_card_networks.find(supported_network);
if (it != remaining_card_networks.end()) {
out_supported_networks->push_back(supported_network);
remaining_card_networks.erase(it);
}
if (kBasicCardNetworks.find(supported_network) !=
kBasicCardNetworks.end()) {
out_basic_card_specified_networks->insert(supported_network);
}
}
}
} else {
// Here |method_data_entry.supported_method| could be a deprecated
// supported network (e.g., "visa"), some invalid string or a URL
// Payment Method Identifier. Capture this last category if the URL
// is valid. A valid URL must have an https scheme and its username and
// password must be empty:
// https://www.w3.org/TR/payment-method-id/#dfn-validate-a-url-based-payment-method-identifier
// Avoid duplicate URLs.
GURL url(method_data_entry.supported_method);
if (url.is_valid() && url.SchemeIs(url::kHttpsScheme) &&
!url.has_username() && !url.has_password()) {
const auto result = url_payment_method_identifiers.insert(url);
if (result.second)
out_url_payment_method_identifiers->push_back(url);
}
}
}
}
void ParseSupportedCardTypes(
const std::vector<PaymentMethodData>& method_data,
std::set<autofill::CreditCard::CardType>* out_supported_card_types_set) {
DCHECK(out_supported_card_types_set->empty());
for (const PaymentMethodData& method_data_entry : method_data) {
// Ignore |supported_types| if |supported_method| is not "basic-card".
if (method_data_entry.supported_method != "basic-card")
continue;
for (const autofill::CreditCard::CardType& card_type :
method_data_entry.supported_types) {
out_supported_card_types_set->insert(card_type);
}
}
// Omitting the card types means all 3 card types are supported.
if (out_supported_card_types_set->empty()) {
out_supported_card_types_set->insert(
autofill::CreditCard::CARD_TYPE_CREDIT);
out_supported_card_types_set->insert(autofill::CreditCard::CARD_TYPE_DEBIT);
out_supported_card_types_set->insert(
autofill::CreditCard::CARD_TYPE_PREPAID);
}
// Let the user decide whether an unknown card type should be used.
out_supported_card_types_set->insert(autofill::CreditCard::CARD_TYPE_UNKNOWN);
}
base::string16 FormatCardNumberForDisplay(const base::string16& card_number) {
base::string16 number = autofill::CreditCard::StripSeparators(card_number);
if (number.empty() || !base::IsAsciiDigit(number[0]))
return card_number;
std::vector<size_t> positions = {4U, 9U, 14U};
if (autofill::CreditCard::GetCardNetwork(number) ==
autofill::kAmericanExpressCard) {
positions = {4U, 11U};
}
static const base::char16 kSeparator = base::ASCIIToUTF16(" ")[0];
for (size_t i : positions) {
if (number.size() > i)
number.insert(i, 1U, kSeparator);
}
return number;
}
} // namespace data_util
} // namespace payments